From 272da1188b20d0046085332665e7d3d3082b29c7 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:41:45 +0100 Subject: [PATCH 01/68] 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 79447cb440..37cbcecd38 100644 --- a/core/src/main/java/org/lflang/AttributeUtils.java +++ b/core/src/main/java/org/lflang/AttributeUtils.java @@ -226,6 +226,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 4ce02d4793..1230debfa4 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; @@ -96,6 +97,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. @@ -157,6 +159,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 ab8b5d3aaa2f817ba77b7f9b439840dacc92e85d Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:47:43 +0100 Subject: [PATCH 02/68] 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 12edb2e693..6964223242 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -723,6 +723,8 @@ else if (globalSTP instanceof CodeExprImpl) } // 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 4daef37b868973eedd706c12eebbe9141a629306 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 21:49:01 +0100 Subject: [PATCH 03/68] Make federates bin directory visible --- .../org/lflang/generator/c/CCompiler.java | 101 +++++++++++------- 1 file changed, 61 insertions(+), 40 deletions(-) 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 12de4474dc..b40a93a5ad 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -49,7 +49,8 @@ import org.lflang.util.LFCommand; /** - * Responsible for creating and executing the necessary CMake command to compile code that is + * Responsible for creating and executing the necessary CMake command to compile + * code that is * generated by the CGenerator. This class uses CMake to compile. * * @author Soroush Bateni @@ -66,7 +67,8 @@ public class CCompiler { MessageReporter messageReporter; /** - * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler produces .cpp files + * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler + * produces .cpp files * instead of .c files and uses a C++ compiler to compiler the code. */ private final boolean cppMode; @@ -77,10 +79,11 @@ public class CCompiler { /** * Create an instance of CCompiler. * - * @param targetConfig The current target configuration. - * @param fileConfig The current file configuration. + * @param targetConfig The current target configuration. + * @param fileConfig The current file configuration. * @param messageReporter Used to report errors. - * @param cppMode Whether the generated code should be compiled as if it were C++. + * @param cppMode Whether the generated code should be compiled as if it + * were C++. */ public CCompiler( TargetConfig targetConfig, @@ -97,8 +100,9 @@ public CCompiler( /** * Run the C compiler by invoking cmake and make. * - * @param generator An instance of GeneratorBase, only used to report error line numbers in the - * Eclipse IDE. + * @param generator An instance of GeneratorBase, only used to report error line + * numbers in the + * Eclipse IDE. * @return true if compilation succeeds, false otherwise. */ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) @@ -109,9 +113,9 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) // avoid any error residue that can occur in CMake from // a previous build. // FIXME: This is slow and only needed if an error - // has previously occurred. Deleting the build directory - // if no prior errors have occurred can prolong the compilation - // substantially. See #1416 for discussion. + // has previously occurred. Deleting the build directory + // if no prior errors have occurred can prolong the compilation + // substantially. See #1416 for discussion. FileUtil.deleteDirectory(buildPath); // Make sure the build directory exists Files.createDirectories(buildPath); @@ -193,15 +197,15 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } /** - * Return a command to compile the specified C file using CMake. This produces a C-specific + * Return a command to compile the specified C file using CMake. This produces a + * C-specific * compile command. */ public LFCommand compileCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - LFCommand command = - commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); + LFCommand command = commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); if (command == null) { messageReporter .nowhere() @@ -220,6 +224,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f String quote = "\""; String srcPath = fileConfig.srcPath.toString(); String rootPath = fileConfig.srcPkgPath.toString(); + String binPath = fileConfig.binPath.toString(); String srcGenPath = fileConfig.getSrcGenPath().toString(); if (separator.equals("\\")) { // Windows requires escaping the backslashes. @@ -228,6 +233,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( @@ -240,13 +246,16 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f + FileUtil.toUnixString(fileConfig.getOutPath().relativize(fileConfig.binPath)), "-DLF_FILE_SEPARATOR='" + quote + separator + quote + "'")); // Add #define for source file directory. - // Do not do this for federated programs because for those, the definition is put + // Do not do this for federated programs because for those, the definition is + // put // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); arguments.add("-DLF_PACKAGE_DIRECTORY='" + quote + rootPath + quote + "'"); arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); + } else { + arguments.add("-DLF_FEDERATES_BIN_DIRECTORY=\"" + quote + binPath + quote + "\""); } arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); @@ -270,29 +279,31 @@ private String buildTypeToCmakeConfig(BuildType type) { } /** - * Return a command to build the specified C file using CMake. This produces a C-specific build + * Return a command to build the specified C file using CMake. This produces a + * C-specific build * command. * - *

Note: It appears that configuration and build cannot happen in one command. Therefore, this + *

+ * Note: It appears that configuration and build cannot happen in one command. + * Therefore, this * is separated into a compile command and a build command. */ public LFCommand buildCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); String cores = String.valueOf(Runtime.getRuntime().availableProcessors()); - LFCommand command = - commandFactory.createCommand( - "cmake", - List.of( - "--build", - ".", - "--target", - "install", - "--parallel", - cores, - "--config", - buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), - buildPath); + LFCommand command = commandFactory.createCommand( + "cmake", + List.of( + "--build", + ".", + "--target", + "install", + "--parallel", + cores, + "--config", + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), + buildPath); if (command == null) { messageReporter .nowhere() @@ -305,8 +316,10 @@ public LFCommand buildCmakeCommand() { } /** - * Return a flash/emulate command using west. If board is null (defaults to qemu_cortex_m3) or - * qemu_* Return a flash command which runs the target as an emulation If ordinary target, return + * Return a flash/emulate command using west. If board is null (defaults to + * qemu_cortex_m3) or + * qemu_* Return a flash command which runs the target as an emulation If + * ordinary target, return * {@code west flash} */ public LFCommand buildWestFlashCommand(PlatformOptions options) { @@ -328,18 +341,23 @@ public LFCommand buildWestFlashCommand(PlatformOptions options) { } /** - * Check if the output produced by CMake has any known and common errors. If a known error is + * Check if the output produced by CMake has any known and common errors. If a + * known error is * detected, a specialized, more informative message is shown. * - *

Errors currently detected: + *

+ * Errors currently detected: * *

    - *
  • C++ compiler used to compile C files: This error shows up as '#error "The - * CMAKE_C_COMPILER is set to a C++ compiler"' in the 'CMakeOutput' string. + *
  • C++ compiler used to compile C files: This error shows up as '#error + * "The + * CMAKE_C_COMPILER is set to a C++ compiler"' in the + * 'CMakeOutput' string. *
* * @param CMakeOutput The captured output from CMake. - * @return true if the provided 'CMakeOutput' contains a known error. false otherwise. + * @return true if the provided 'CMakeOutput' contains a known error. false + * otherwise. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { @@ -369,8 +387,10 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { * Produces the filename including the target-specific extension * * @param fileName The base name of the file without any extensions - * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the compiler produces - * .cpp files instead of .c files and uses a C++ compiler to compiler the code. + * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the + * compiler produces + * .cpp files instead of .c files and uses a C++ compiler to + * compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { return fileName + getFileExtension(cppMode, targetConfig); @@ -379,8 +399,9 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t /** * Return the file extension of the output source files. * - * @param cppMode Whether we are building C code using a C++ compiler. - * @param targetConfig The target configuration that parameterizes the build process. + * @param cppMode Whether we are building C code using a C++ compiler. + * @param targetConfig The target configuration that parameterizes the build + * process. */ static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { From dffabc48d0dcffca2259340bcd3512495d251f51 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 13:54:42 +0100 Subject: [PATCH 04/68] 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 eb5eb218656badcdad973a5da470f8d8ead012e5 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 11 Jan 2024 14:08:23 +0100 Subject: [PATCH 05/68] 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 eb721cf032..f208a82c3f 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -531,6 +531,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 dc95f451cbde681229dd6754ef478f537c429b18 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 14 Feb 2024 16:21:02 +0100 Subject: [PATCH 06/68] 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 03137a0295..75db4d6e9d 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 03137a029588e5eec364f3f1d6c2ab99a22f66de +Subproject commit 75db4d6e9d5cb7b31292239f20876fa933e0edf0 From 612d05758a12be9093dba90b27882e8e208fd5c2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 19 Feb 2024 16:27:09 +0100 Subject: [PATCH 07/68] 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 10816dc111..f9a059b990 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 ee48c1d6d1e2beb8b29d0865efca1a2075c937e0 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 19 Feb 2024 16:33:32 +0100 Subject: [PATCH 08/68] 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 f9a059b990..c3290ad5a1 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 0766e0392110c889a042ca380ce09f0a93f9f5af Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:16:12 +0100 Subject: [PATCH 09/68] 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 49251821f3f5661d5f353484792bcc9daf7c0179 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 22:56:28 +0100 Subject: [PATCH 10/68] 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 1230debfa4..7d769a731e 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -161,7 +161,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 f208a82c3f..bcfd861bf2 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -533,10 +533,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 94a10c2d7e6838cf0d080ece6431af31ff7ce60f Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 23:13:11 +0100 Subject: [PATCH 11/68] 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 7d769a731e..b81e7c10a4 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,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 bbca7ac414b2629bdc986f40afd67e1c8f7f58c2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 21 Feb 2024 12:26:09 +0100 Subject: [PATCH 12/68] 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 b81e7c10a4..7d769a731e 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -160,6 +160,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 6bfa7c890a44f46b2489adeaa3e5c293b6e97654 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 13/68] 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 c3290ad5a1..171222c966 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 51eb1354aba44d7fc758e98c5426e3275c3569b2 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 14/68] 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 e7b95059b8e8d7828262df9586fa9e591a61c2b6 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 09:57:18 +0100 Subject: [PATCH 15/68] 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 bcfd861bf2..10ad9c2c11 100644 --- a/core/src/main/java/org/lflang/validation/LFValidator.java +++ b/core/src/main/java/org/lflang/validation/LFValidator.java @@ -536,8 +536,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 3624e6b549e8bb1fd8847027a27646009751d13a Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 09:58:39 +0100 Subject: [PATCH 16/68] 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 740e00681685c530b071ed3ae6fbf520e41ed589 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 10:54:28 +0100 Subject: [PATCH 17/68] 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 de3c0ba4ed0c73f48a222b5be7bf62a171f65bb3 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 11:12:37 +0100 Subject: [PATCH 18/68] 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 ad48c812b874806786b38a810eac1539b9af5c82 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 11:23:58 +0100 Subject: [PATCH 19/68] 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 1671246f39124c5672989f92f66f6116f7f1c7ea Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 22 Feb 2024 12:14:46 +0100 Subject: [PATCH 20/68] 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 c99fe39830bc8457d8b75cc639804bd433395d87 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 18:38:46 +0100 Subject: [PATCH 21/68] Add TransientStatePersistence test and align reactor-c --- .../transient/TransientStatePersistence.lf | 191 ++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 test/C/src/federated/transient/TransientStatePersistence.lf 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 2f0be1c2c30ba5d2ceda398733f2505e29734ee6 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 29 Feb 2024 19:33:39 +0100 Subject: [PATCH 22/68] 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 b1a743624520ab2cae4499e6219a95cfc0057399 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 05:58:59 +0100 Subject: [PATCH 23/68] 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 5c1d050999c7402753291399292ed655ffa5a3de Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 14:15:40 +0100 Subject: [PATCH 24/68] 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 35903aba2938179af301907a8788760e2fc40493 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 18 Mar 2024 14:16:16 +0100 Subject: [PATCH 25/68] 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 ff93cd7278241b371b4ff0f6d12ac8bf63ad70f9 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 19 Mar 2024 00:05:39 +0100 Subject: [PATCH 26/68] 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 4d8849f80a2cd363905ae17ae4bb57c1e4689b20 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 24 Apr 2024 13:00:51 +0100 Subject: [PATCH 27/68] 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 9167a314b6fcdf76dfc9938a3ce3a7eab18faba8 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 18 May 2024 09:01:42 +0100 Subject: [PATCH 28/68] 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 6267fcb37a706e48e68dd2c63f2a2a0d9a4e636e Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 19 Jun 2024 22:16:15 +0100 Subject: [PATCH 29/68] 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 d518b37962e08cca6ae8376fa6682036689856cf Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 20 Jun 2024 09:55:33 +0100 Subject: [PATCH 30/68] Include LF_FEDERATES_BIN_DIRECTORY in cmake for federaes + Align reactor-c --- .../federated/extensions/CExtensionUtils.java | 162 ++++++++++-------- 1 file changed, 93 insertions(+), 69 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 ad982431a2..768dcdb648 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) { @@ -92,8 +95,11 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -109,8 +115,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.staToNetworkActionMap.get(federate.staaOffsets.get(i)); + List networkActions = federate.staToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( @@ -143,7 +148,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 @@ -151,7 +157,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 @@ -163,15 +170,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. @@ -215,11 +230,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())); } @@ -232,16 +245,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() @@ -263,12 +280,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) { @@ -299,10 +319,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(); @@ -324,7 +343,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 @@ -397,14 +417,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( @@ -461,26 +480,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); } @@ -489,39 +509,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); } @@ -542,7 +564,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) { From 3c5a6344d57957500124f8efbc06c03eddc8cf55 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 30 Dec 2024 09:31:21 +0100 Subject: [PATCH 31/68] 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 75db4d6e9d..c6e43ee0bc 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 75db4d6e9d5cb7b31292239f20876fa933e0edf0 +Subproject commit c6e43ee0bc416d83e8f29a062b975f75516351cc From 428fd00c183832f681482f7bf18fc3f6d49e57ce Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Tue, 20 Feb 2024 21:49:01 +0100 Subject: [PATCH 32/68] Make federates bin directory visible --- 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 c6e43ee0bc..fe03b3f0e6 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit c6e43ee0bc416d83e8f29a062b975f75516351cc +Subproject commit fe03b3f0e6ecdf201d5323a341a2ab7e82a2818a From 7d8638e86b5e4c07fe55af49b4d034d4be8696ed Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 20 Jun 2024 09:55:33 +0100 Subject: [PATCH 33/68] Include LF_FEDERATES_BIN_DIRECTORY is cmake for federaes + Align reactor-c --- .../org/lflang/federated/extensions/CExtensionUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 768dcdb648..70d6a3ad06 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -115,7 +115,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.staToNetworkActionMap.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( @@ -332,7 +332,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_FILE_SEPARATOR=\"" + File.separator + "\")"); + cmakeIncludeCode.pr( + "add_compile_definitions(LF_FEDERATES_BIN_DIRECTORY=\"" + fileConfig.getFedBinPath() + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); } From 7dca421a2d4101813378c05078cee4804626a075 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 15 Jul 2024 10:58:30 -0400 Subject: [PATCH 34/68] Support zero-delay cycles --- .../federated/extensions/CExtension.java | 24 ++++++++++++++++--- .../federated/extensions/CExtensionUtils.java | 14 +++++++++++ .../federated/generator/FedASTUtils.java | 5 ++-- .../federated/generator/FederateInstance.java | 5 ++++ 4 files changed, 43 insertions(+), 5 deletions(-) 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 6964223242..df2617d197 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -553,15 +553,33 @@ protected String makePreamble( // that handles incoming network messages destined to the specified // port. This will only be used if there are federates. int numOfNetworkActions = federate.networkMessageActions.size(); + int numZDCNetworkActions = federate.zeroDelayCycleNetworkMessageActions.size(); code.pr( """ interval_t _lf_action_delay_table[%1$s]; lf_action_base_t* _lf_action_table[%1$s]; size_t _lf_action_table_size = %1$s; - lf_action_base_t* _lf_zero_delay_cycle_action_table[%2$s]; - size_t _lf_zero_delay_cycle_action_table_size = %2$s; """ - .formatted(numOfNetworkActions, federate.zeroDelayCycleNetworkMessageActions.size())); + .formatted(numOfNetworkActions)); + if (numZDCNetworkActions > 0) { + code.pr( + """ + lf_action_base_t* _lf_zero_delay_cycle_action_table[%1$s]; + size_t _lf_zero_delay_cycle_action_table_size = %1$s; + uint16_t _lf_zero_delay_cycle_upstream_ids[%1$s]; + bool _lf_zero_delay_cycle_upstream_disconnected[%1$s] = { false }; + """ + .formatted(numZDCNetworkActions)); + } else { + // Make sure these symbols are defined, even though only size will be used. + code.pr( + """ + lf_action_base_t** _lf_zero_delay_cycle_action_table = NULL; + size_t _lf_zero_delay_cycle_action_table_size = 0; + uint16_t* _lf_zero_delay_cycle_upstream_ids = NULL; + bool* _lf_zero_delay_cycle_upstream_disconnected[%1$s] = NULL; + """); + } int numOfNetworkReactions = federate.networkReceiverReactions.size(); code.pr( 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 70d6a3ad06..8aa98e52b0 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -64,6 +64,7 @@ public static String initializeTriggersForNetworkActions( var actionInstance = reactor.lookupActionInstance(action); var trigger = CUtil.actionRef(actionInstance, null); var delay = federate.networkMessageActionDelays.get(i); + var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(i); code.pr( "_lf_action_delay_table[" + actionTableCount @@ -80,6 +81,19 @@ public static String initializeTriggersForNetworkActions( code.pr( trigger + ".source_id = " + federate.networkMessageSourceFederate.get(i).id + "; \\"); if (federate.zeroDelayCycleNetworkMessageActions.contains(action)) { + code.pr( + "_lf_zero_delay_cycle_upstream_ids[" + + zeroDelayActionTableCount + + "] = " + + upstream.id + + "; \\"); + if (federate.isTransient) { + // Transient federates are assumed to be initially disconnected. + code.pr( + "_lf_zero_delay_cycle_upstream_disconnected[" + + zeroDelayActionTableCount + + "] = true; \\"); + } code.pr( "_lf_zero_delay_cycle_action_table[" + zeroDelayActionTableCount++ diff --git a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java index 5973b04dfd..3355152b48 100644 --- a/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java +++ b/core/src/main/java/org/lflang/federated/generator/FedASTUtils.java @@ -287,9 +287,10 @@ private static void addNetworkReceiverReactor( connection.dstFederate.networkMessageSourceFederate.add(connection.srcFederate); connection.dstFederate.networkMessageActionDelays.add(connection.getDefinition().getDelay()); if (connection.srcFederate.isInZeroDelayCycle() - && connection.getDefinition().getDelay() == null) + && connection.getDefinition().getDelay() == null) { connection.dstFederate.zeroDelayCycleNetworkMessageActions.add(networkAction); - + connection.dstFederate.zeroDelayCycleNetworkUpstreamFeds.add(connection.srcFederate); + } // Get the largest STAA for any reaction triggered by the destination port. TimeValue maxSTAA = findMaxSTAA(connection, coordination); 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 7d769a731e..72abd76f7d 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -193,6 +193,11 @@ public Instantiation getInstantiation() { */ public List zeroDelayCycleNetworkMessageActions = new ArrayList<>(); + /** + * List of upstream federates corresponding to actions in the zeroDelayCycleNetworkMessageActions list. + */ + public List zeroDelayCycleNetworkUpstreamFeds = new ArrayList<>(); + /** * A set of federates with which this federate has an inbound connection There will only be one * physical connection even if federate A has defined multiple physical connections to federate B. From 07fd0cf5adeea6fe49644ebb289b6f9b637147ca Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 15 Jul 2024 16:31:01 -0400 Subject: [PATCH 35/68] Fixed compile and Docker errors --- .../java/org/lflang/federated/extensions/CExtension.java | 2 +- .../org/lflang/federated/extensions/CExtensionUtils.java | 2 +- core/src/main/java/org/lflang/generator/c/CCompiler.java | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) 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 df2617d197..c2b34e542e 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -577,7 +577,7 @@ protected String makePreamble( lf_action_base_t** _lf_zero_delay_cycle_action_table = NULL; size_t _lf_zero_delay_cycle_action_table_size = 0; uint16_t* _lf_zero_delay_cycle_upstream_ids = NULL; - bool* _lf_zero_delay_cycle_upstream_disconnected[%1$s] = NULL; + bool* _lf_zero_delay_cycle_upstream_disconnected = NULL; """); } 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 8aa98e52b0..9fb7c82819 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -64,7 +64,6 @@ public static String initializeTriggersForNetworkActions( var actionInstance = reactor.lookupActionInstance(action); var trigger = CUtil.actionRef(actionInstance, null); var delay = federate.networkMessageActionDelays.get(i); - var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(i); code.pr( "_lf_action_delay_table[" + actionTableCount @@ -81,6 +80,7 @@ public static String initializeTriggersForNetworkActions( code.pr( trigger + ".source_id = " + federate.networkMessageSourceFederate.get(i).id + "; \\"); if (federate.zeroDelayCycleNetworkMessageActions.contains(action)) { + var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(i); code.pr( "_lf_zero_delay_cycle_upstream_ids[" + zeroDelayActionTableCount 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 b40a93a5ad..748e1c410f 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,6 +40,7 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CompilerProperty; +import org.lflang.target.property.DockerProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.Option; import org.lflang.target.property.PlatformProperty.PlatformOptions; @@ -235,6 +236,10 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f srcGenPath = srcGenPath.replaceAll("\\\\", "\\\\\\\\"); binPath = binPath.replaceAll("\\\\", "\\\\\\\\"); } + if (targetConfig.get(DockerProperty.INSTANCE).enabled()) { + // Docker seems to require an extra level of quotes. + maybeQuote = "\\\""; + } arguments.addAll( List.of( "-DCMAKE_BUILD_TYPE=" From 1ce4da72543b296fb47723fc35ef4a0be3315147 Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 15 Jul 2024 16:37:02 -0400 Subject: [PATCH 36/68] Format --- .../federated/extensions/CExtension.java | 4 +- .../federated/extensions/CExtensionUtils.java | 168 ++++++++---------- .../federated/generator/FederateInstance.java | 3 +- 3 files changed, 78 insertions(+), 97 deletions(-) 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 c2b34e542e..e569237629 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -560,7 +560,7 @@ protected String makePreamble( lf_action_base_t* _lf_action_table[%1$s]; size_t _lf_action_table_size = %1$s; """ - .formatted(numOfNetworkActions)); + .formatted(numOfNetworkActions)); if (numZDCNetworkActions > 0) { code.pr( """ @@ -569,7 +569,7 @@ protected String makePreamble( uint16_t _lf_zero_delay_cycle_upstream_ids[%1$s]; bool _lf_zero_delay_cycle_upstream_disconnected[%1$s] = { false }; """ - .formatted(numZDCNetworkActions)); + .formatted(numZDCNetworkActions)); } else { // Make sure these symbols are defined, even though only size will be used. code.pr( 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 9fb7c82819..4d950bd588 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -36,20 +36,17 @@ 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) { @@ -82,7 +79,7 @@ public static String initializeTriggersForNetworkActions( if (federate.zeroDelayCycleNetworkMessageActions.contains(action)) { var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(i); code.pr( - "_lf_zero_delay_cycle_upstream_ids[" + "_lf_zero_delay_cycle_upstream_ids[" + zeroDelayActionTableCount + "] = " + upstream.id @@ -90,7 +87,7 @@ public static String initializeTriggersForNetworkActions( if (federate.isTransient) { // Transient federates are assumed to be initially disconnected. code.pr( - "_lf_zero_delay_cycle_upstream_disconnected[" + "_lf_zero_delay_cycle_upstream_disconnected[" + zeroDelayActionTableCount + "] = true; \\"); } @@ -109,11 +106,8 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -129,7 +123,8 @@ 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( @@ -162,8 +157,7 @@ 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 @@ -184,23 +178,15 @@ 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. @@ -244,9 +230,11 @@ 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())); } @@ -259,15 +247,12 @@ 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 + * @see Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { @@ -294,15 +279,12 @@ 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 + * @see Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -333,9 +315,10 @@ 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(); @@ -347,7 +330,9 @@ public static void generateCMakeInclude( cmakeIncludeCode.pr( "add_compile_definitions(LF_SOURCE_GEN_DIRECTORY=\"" + fileConfig.getSrcGenPath() + "\")"); cmakeIncludeCode.pr( - "add_compile_definitions(LF_FEDERATES_BIN_DIRECTORY=\"" + fileConfig.getFedBinPath() + "\")"); + "add_compile_definitions(LF_FEDERATES_BIN_DIRECTORY=\"" + + fileConfig.getFedBinPath() + + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); } @@ -358,8 +343,7 @@ 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 @@ -432,13 +416,14 @@ 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( @@ -495,27 +480,26 @@ 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); } @@ -524,41 +508,39 @@ 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); } @@ -579,9 +561,7 @@ 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/java/org/lflang/federated/generator/FederateInstance.java b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java index 72abd76f7d..e443650eb2 100644 --- a/core/src/main/java/org/lflang/federated/generator/FederateInstance.java +++ b/core/src/main/java/org/lflang/federated/generator/FederateInstance.java @@ -194,7 +194,8 @@ public Instantiation getInstantiation() { public List zeroDelayCycleNetworkMessageActions = new ArrayList<>(); /** - * List of upstream federates corresponding to actions in the zeroDelayCycleNetworkMessageActions list. + * List of upstream federates corresponding to actions in the zeroDelayCycleNetworkMessageActions + * list. */ public List zeroDelayCycleNetworkUpstreamFeds = new ArrayList<>(); From 8390155a96efe0418ab856f2e65d67ba0843f45d Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 17 Jul 2024 12:22:23 +0100 Subject: [PATCH 37/68] Fix code printing of eroDelayCycleNetworkUpstreamFeds --- .../federated/extensions/CExtensionUtils.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 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 4d950bd588..c987b2b143 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -77,13 +77,15 @@ public static String initializeTriggersForNetworkActions( code.pr( trigger + ".source_id = " + federate.networkMessageSourceFederate.get(i).id + "; \\"); if (federate.zeroDelayCycleNetworkMessageActions.contains(action)) { - var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(i); - code.pr( - "_lf_zero_delay_cycle_upstream_ids[" - + zeroDelayActionTableCount - + "] = " - + upstream.id - + "; \\"); + for (int j = 0; j < federate.zeroDelayCycleNetworkUpstreamFeds.size(); ++j) { + var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(j); + code.pr( + "_lf_zero_delay_cycle_upstream_ids[" + + zeroDelayActionTableCount + + "] = " + + upstream.id + + "; \\"); + } if (federate.isTransient) { // Transient federates are assumed to be initially disconnected. code.pr( From 1e6a1b16b13cf8b725d4a7f2dce3f8ee82c8a42a Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Wed, 17 Jul 2024 09:03:43 -0400 Subject: [PATCH 38/68] Corrected upstream settings --- .../federated/extensions/CExtensionUtils.java | 159 ++++++++++-------- 1 file changed, 89 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 c987b2b143..2c24399622 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -36,24 +36,26 @@ 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) { CodeBuilder code = new CodeBuilder(); if (!federate.networkMessageActions.isEmpty()) { var actionTableCount = 0; - var zeroDelayActionTableCount = 0; for (int i = 0; i < federate.networkMessageActions.size(); ++i) { // Find the corresponding ActionInstance. Action action = federate.networkMessageActions.get(i); @@ -90,12 +92,12 @@ public static String initializeTriggersForNetworkActions( // Transient federates are assumed to be initially disconnected. code.pr( "_lf_zero_delay_cycle_upstream_disconnected[" - + zeroDelayActionTableCount + + j + "] = true; \\"); } code.pr( "_lf_zero_delay_cycle_action_table[" - + zeroDelayActionTableCount++ + + j + "] = (lf_action_base_t*)&" + trigger + "; \\"); @@ -108,8 +110,11 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -125,8 +130,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( @@ -159,7 +163,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 @@ -180,15 +185,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. @@ -232,11 +245,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())); } @@ -249,12 +260,14 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { @@ -281,12 +294,14 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -317,10 +332,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(); @@ -345,7 +359,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 @@ -418,14 +433,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( @@ -482,26 +496,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); } @@ -510,39 +525,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); } @@ -563,7 +580,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) { From 9cf954d8554b35417a7c8967601d8e2bea3ef9e5 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 24 Jul 2024 17:23:41 +0100 Subject: [PATCH 39/68] Fix merge of maybeQuote in CCmpiler + Align reactor-c --- .../main/java/org/lflang/generator/c/CCompiler.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 748e1c410f..113f523913 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -222,7 +222,7 @@ public LFCommand compileCmakeCommand() { private static List cmakeOptions(TargetConfig targetConfig, FileConfig fileConfig) { List arguments = new ArrayList<>(); String separator = File.separator; - String quote = "\""; + String maybeQuote = ""; // Windows seems to require extra level of quoting. String srcPath = fileConfig.srcPath.toString(); String rootPath = fileConfig.srcPkgPath.toString(); String binPath = fileConfig.binPath.toString(); @@ -230,7 +230,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f if (separator.equals("\\")) { // Windows requires escaping the backslashes. separator = "\\\\\\\\"; - quote = "\\\""; + maybeQuote = "\\\""; srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); rootPath = rootPath.replaceAll("\\\\", "\\\\\\\\"); srcGenPath = srcGenPath.replaceAll("\\\\", "\\\\\\\\"); @@ -249,16 +249,16 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), "-DCMAKE_INSTALL_BINDIR=" + FileUtil.toUnixString(fileConfig.getOutPath().relativize(fileConfig.binPath)), - "-DLF_FILE_SEPARATOR='" + quote + separator + quote + "'")); + "-DLF_FILE_SEPARATOR='" + maybeQuote + separator + maybeQuote + "'")); // Add #define for source file directory. // Do not do this for federated programs because for those, the definition is // put // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path - arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); - arguments.add("-DLF_PACKAGE_DIRECTORY='" + quote + rootPath + quote + "'"); - arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); + 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=\"" + quote + binPath + quote + "\""); } From d1ac2e732e8227a945155f61c3381b58e5a11b27 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 7 Aug 2024 18:59:17 +0100 Subject: [PATCH 40/68] Revert quotes specification in cmakeOptions() --- .../org/lflang/generator/c/CCompiler.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) 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 113f523913..931554a243 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -222,23 +222,17 @@ public LFCommand compileCmakeCommand() { private static List cmakeOptions(TargetConfig targetConfig, FileConfig fileConfig) { List arguments = new ArrayList<>(); String separator = File.separator; - String maybeQuote = ""; // Windows seems to require extra level of quoting. + String quote = "\""; String srcPath = fileConfig.srcPath.toString(); String rootPath = fileConfig.srcPkgPath.toString(); - String binPath = fileConfig.binPath.toString(); String srcGenPath = fileConfig.getSrcGenPath().toString(); if (separator.equals("\\")) { // Windows requires escaping the backslashes. separator = "\\\\\\\\"; - maybeQuote = "\\\""; + quote = "\\\""; srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); rootPath = rootPath.replaceAll("\\\\", "\\\\\\\\"); srcGenPath = srcGenPath.replaceAll("\\\\", "\\\\\\\\"); - binPath = binPath.replaceAll("\\\\", "\\\\\\\\"); - } - if (targetConfig.get(DockerProperty.INSTANCE).enabled()) { - // Docker seems to require an extra level of quotes. - maybeQuote = "\\\""; } arguments.addAll( List.of( @@ -249,18 +243,17 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f "-DCMAKE_INSTALL_PREFIX=" + FileUtil.toUnixString(fileConfig.getOutPath()), "-DCMAKE_INSTALL_BINDIR=" + FileUtil.toUnixString(fileConfig.getOutPath().relativize(fileConfig.binPath)), - "-DLF_FILE_SEPARATOR='" + maybeQuote + separator + maybeQuote + "'")); + "-DLF_FILE_SEPARATOR='" + quote + separator + quote + "'")); // Add #define for source file directory. // Do not do this for federated programs because for those, the definition is // put // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path - 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 + "'"); + arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); + arguments.add("-DLF_PACKAGE_DIRECTORY='" + quote + rootPath + quote + "'"); } else { - arguments.add("-DLF_FEDERATES_BIN_DIRECTORY=\"" + quote + binPath + quote + "\""); + arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); } arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); From ec3b1904ff684625c35a218ec31b1c7ca0a30e02 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 7 Aug 2024 19:00:35 +0100 Subject: [PATCH 41/68] Remove no more needed import --- core/src/main/java/org/lflang/generator/c/CCompiler.java | 1 - 1 file changed, 1 deletion(-) 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 931554a243..fb1871d113 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -40,7 +40,6 @@ import org.lflang.target.TargetConfig; import org.lflang.target.property.BuildTypeProperty; import org.lflang.target.property.CompilerProperty; -import org.lflang.target.property.DockerProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.Option; import org.lflang.target.property.PlatformProperty.PlatformOptions; From 2e349d2ba0f7c5f7c49ce0431941ef3b7ca65436 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 7 Aug 2024 19:01:41 +0100 Subject: [PATCH 42/68] Update the preamble in transients tests --- test/C/src/federated/transient/TransientDownstreamWithTimer.lf | 1 + .../federated/transient/TransientDownstreamWithTwoUpstream.lf | 1 + test/C/src/federated/transient/TransientHotSwap.lf | 1 + test/C/src/federated/transient/TransientStatePersistence.lf | 1 + 4 files changed, 4 insertions(+) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index a403057e48..8a493b432e 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -13,6 +13,7 @@ target C { preamble {= #include #include + #include "federate.h" =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 49960b05b4..3fac7d04ac 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -19,6 +19,7 @@ import Middle from "TransientDownstreamWithTimer.lf" preamble {= #include #include + #include "federate.h" =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index a4c986d3d4..4f49bf74e4 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -18,6 +18,7 @@ import Down from "TransientDownstreamWithTimer.lf" preamble {= #include #include + #include "federate.h" =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 71f3ed2b2d..29b932853b 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -13,6 +13,7 @@ target C { preamble {= #include #include + #include "federate.h" // The internal federate state to be persistent across executions typedef struct federate_state_t { From ce66d8b1e7bc8bf284c44767fdec916828e377f6 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 7 Aug 2024 19:43:37 +0100 Subject: [PATCH 43/68] Remove compile definition of the federate bin path + Align reactor-c --- .../java/org/lflang/federated/extensions/CExtensionUtils.java | 4 ---- 1 file changed, 4 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 2c24399622..d1b014f4cb 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -345,10 +345,6 @@ 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()); } From aa8a2eed497eccf3c8cfe90e04e253b3f1726962 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 7 Aug 2024 19:52:36 +0100 Subject: [PATCH 44/68] Run spotles --- .../federated/extensions/CExtensionUtils.java | 5 +- .../org/lflang/generator/c/CCompiler.java | 88 ++++++++----------- 2 files changed, 37 insertions(+), 56 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 d1b014f4cb..355b3fadda 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -90,10 +90,7 @@ public static String initializeTriggersForNetworkActions( } if (federate.isTransient) { // Transient federates are assumed to be initially disconnected. - code.pr( - "_lf_zero_delay_cycle_upstream_disconnected[" - + j - + "] = true; \\"); + code.pr("_lf_zero_delay_cycle_upstream_disconnected[" + j + "] = true; \\"); } code.pr( "_lf_zero_delay_cycle_action_table[" 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 fb1871d113..2e61aaae49 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -49,8 +49,7 @@ import org.lflang.util.LFCommand; /** - * Responsible for creating and executing the necessary CMake command to compile - * code that is + * Responsible for creating and executing the necessary CMake command to compile code that is * generated by the CGenerator. This class uses CMake to compile. * * @author Soroush Bateni @@ -67,8 +66,7 @@ public class CCompiler { MessageReporter messageReporter; /** - * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler - * produces .cpp files + * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler produces .cpp files * instead of .c files and uses a C++ compiler to compiler the code. */ private final boolean cppMode; @@ -79,11 +77,10 @@ public class CCompiler { /** * Create an instance of CCompiler. * - * @param targetConfig The current target configuration. - * @param fileConfig The current file configuration. + * @param targetConfig The current target configuration. + * @param fileConfig The current file configuration. * @param messageReporter Used to report errors. - * @param cppMode Whether the generated code should be compiled as if it - * were C++. + * @param cppMode Whether the generated code should be compiled as if it were C++. */ public CCompiler( TargetConfig targetConfig, @@ -100,9 +97,8 @@ public CCompiler( /** * Run the C compiler by invoking cmake and make. * - * @param generator An instance of GeneratorBase, only used to report error line - * numbers in the - * Eclipse IDE. + * @param generator An instance of GeneratorBase, only used to report error line numbers in the + * Eclipse IDE. * @return true if compilation succeeds, false otherwise. */ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) @@ -197,15 +193,15 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } /** - * Return a command to compile the specified C file using CMake. This produces a - * C-specific + * Return a command to compile the specified C file using CMake. This produces a C-specific * compile command. */ public LFCommand compileCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - LFCommand command = commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); + LFCommand command = + commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); if (command == null) { messageReporter .nowhere() @@ -276,31 +272,29 @@ private String buildTypeToCmakeConfig(BuildType type) { } /** - * Return a command to build the specified C file using CMake. This produces a - * C-specific build + * Return a command to build the specified C file using CMake. This produces a C-specific build * command. * - *

- * Note: It appears that configuration and build cannot happen in one command. - * Therefore, this + *

Note: It appears that configuration and build cannot happen in one command. Therefore, this * is separated into a compile command and a build command. */ public LFCommand buildCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); String cores = String.valueOf(Runtime.getRuntime().availableProcessors()); - LFCommand command = commandFactory.createCommand( - "cmake", - List.of( - "--build", - ".", - "--target", - "install", - "--parallel", - cores, - "--config", - buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), - buildPath); + LFCommand command = + commandFactory.createCommand( + "cmake", + List.of( + "--build", + ".", + "--target", + "install", + "--parallel", + cores, + "--config", + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), + buildPath); if (command == null) { messageReporter .nowhere() @@ -313,10 +307,8 @@ public LFCommand buildCmakeCommand() { } /** - * Return a flash/emulate command using west. If board is null (defaults to - * qemu_cortex_m3) or - * qemu_* Return a flash command which runs the target as an emulation If - * ordinary target, return + * Return a flash/emulate command using west. If board is null (defaults to qemu_cortex_m3) or + * qemu_* Return a flash command which runs the target as an emulation If ordinary target, return * {@code west flash} */ public LFCommand buildWestFlashCommand(PlatformOptions options) { @@ -338,23 +330,18 @@ public LFCommand buildWestFlashCommand(PlatformOptions options) { } /** - * Check if the output produced by CMake has any known and common errors. If a - * known error is + * Check if the output produced by CMake has any known and common errors. If a known error is * detected, a specialized, more informative message is shown. * - *

- * Errors currently detected: + *

Errors currently detected: * *

    - *
  • C++ compiler used to compile C files: This error shows up as '#error - * "The - * CMAKE_C_COMPILER is set to a C++ compiler"' in the - * 'CMakeOutput' string. + *
  • C++ compiler used to compile C files: This error shows up as '#error "The + * CMAKE_C_COMPILER is set to a C++ compiler"' in the 'CMakeOutput' string. *
* * @param CMakeOutput The captured output from CMake. - * @return true if the provided 'CMakeOutput' contains a known error. false - * otherwise. + * @return true if the provided 'CMakeOutput' contains a known error. false otherwise. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { @@ -384,10 +371,8 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { * Produces the filename including the target-specific extension * * @param fileName The base name of the file without any extensions - * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the - * compiler produces - * .cpp files instead of .c files and uses a C++ compiler to - * compiler the code. + * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the compiler produces + * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { return fileName + getFileExtension(cppMode, targetConfig); @@ -396,9 +381,8 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t /** * Return the file extension of the output source files. * - * @param cppMode Whether we are building C code using a C++ compiler. - * @param targetConfig The target configuration that parameterizes the build - * process. + * @param cppMode Whether we are building C code using a C++ compiler. + * @param targetConfig The target configuration that parameterizes the build process. */ static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { From 2b8cb9b405e02eb3a48ad99a8a0a516f68154ecd Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 14 Aug 2024 07:50:28 +0100 Subject: [PATCH 45/68] Apply formatter --- .../java/org/lflang/federated/extensions/CExtensionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 355b3fadda..078d9de7be 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -127,7 +127,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.staToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( From 060c7e90c6984d5b7b4d5d95c4ae16ffe0be9c19 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 2 Dec 2024 09:19:22 +0100 Subject: [PATCH 46/68] Apply spotless --- .../federated/extensions/CExtensionUtils.java | 154 ++++++++---------- 1 file changed, 67 insertions(+), 87 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 078d9de7be..90cccdcd16 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -36,20 +36,17 @@ 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) { @@ -107,11 +104,8 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -127,7 +121,8 @@ 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.staToNetworkActionMap.get(federate.staaOffsets.get(i)); + List networkActions = + federate.staToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( @@ -160,8 +155,7 @@ 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 @@ -182,23 +176,15 @@ 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. @@ -242,9 +228,11 @@ 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())); } @@ -257,14 +245,12 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { @@ -291,14 +277,12 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -329,9 +313,10 @@ 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(); @@ -352,8 +337,7 @@ 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 @@ -426,13 +410,14 @@ 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( @@ -489,27 +474,26 @@ 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); } @@ -518,41 +502,39 @@ 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); } @@ -573,9 +555,7 @@ 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) { From 34b6cb608399ee837dffecd665c49b2d43d8a916 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 2 Dec 2024 10:13:05 +0100 Subject: [PATCH 47/68] Attempt to pass tests by manually adding prototypes to lf code --- .../C/src/federated/transient/TransientDownstreamWithTimer.lf | 3 ++- .../federated/transient/TransientDownstreamWithTwoUpstream.lf | 3 ++- test/C/src/federated/transient/TransientHotSwap.lf | 3 ++- test/C/src/federated/transient/TransientStatePersistence.lf | 4 +++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 8a493b432e..b04abd3fd6 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -13,7 +13,8 @@ target C { preamble {= #include #include - #include "federate.h" + char* lf_get_federates_bin_directory(); + const char* lf_get_federation_id(); =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 3fac7d04ac..8ccd6db787 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -19,7 +19,8 @@ import Middle from "TransientDownstreamWithTimer.lf" preamble {= #include #include - #include "federate.h" + char* lf_get_federates_bin_directory(); + const char* lf_get_federation_id(); =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 4f49bf74e4..d0dbf3afbd 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -18,7 +18,8 @@ import Down from "TransientDownstreamWithTimer.lf" preamble {= #include #include - #include "federate.h" + char* lf_get_federates_bin_directory(); + const char* lf_get_federation_id(); =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 29b932853b..5d4a7f600f 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -13,7 +13,9 @@ target C { preamble {= #include #include - #include "federate.h" + + char* lf_get_federates_bin_directory(); + const char* lf_get_federation_id(); // The internal federate state to be persistent across executions typedef struct federate_state_t { From 9705333767c4a7e89ca6b860a12ec8d68d656cd9 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 2 Dec 2024 13:33:16 +0100 Subject: [PATCH 48/68] Attempt to fix redundant declaration error --- .../org/lflang/generator/c/CCompiler.java | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) 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 2e61aaae49..fb1871d113 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -49,7 +49,8 @@ import org.lflang.util.LFCommand; /** - * Responsible for creating and executing the necessary CMake command to compile code that is + * Responsible for creating and executing the necessary CMake command to compile + * code that is * generated by the CGenerator. This class uses CMake to compile. * * @author Soroush Bateni @@ -66,7 +67,8 @@ public class CCompiler { MessageReporter messageReporter; /** - * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler produces .cpp files + * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler + * produces .cpp files * instead of .c files and uses a C++ compiler to compiler the code. */ private final boolean cppMode; @@ -77,10 +79,11 @@ public class CCompiler { /** * Create an instance of CCompiler. * - * @param targetConfig The current target configuration. - * @param fileConfig The current file configuration. + * @param targetConfig The current target configuration. + * @param fileConfig The current file configuration. * @param messageReporter Used to report errors. - * @param cppMode Whether the generated code should be compiled as if it were C++. + * @param cppMode Whether the generated code should be compiled as if it + * were C++. */ public CCompiler( TargetConfig targetConfig, @@ -97,8 +100,9 @@ public CCompiler( /** * Run the C compiler by invoking cmake and make. * - * @param generator An instance of GeneratorBase, only used to report error line numbers in the - * Eclipse IDE. + * @param generator An instance of GeneratorBase, only used to report error line + * numbers in the + * Eclipse IDE. * @return true if compilation succeeds, false otherwise. */ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) @@ -193,15 +197,15 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } /** - * Return a command to compile the specified C file using CMake. This produces a C-specific + * Return a command to compile the specified C file using CMake. This produces a + * C-specific * compile command. */ public LFCommand compileCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - LFCommand command = - commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); + LFCommand command = commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); if (command == null) { messageReporter .nowhere() @@ -272,29 +276,31 @@ private String buildTypeToCmakeConfig(BuildType type) { } /** - * Return a command to build the specified C file using CMake. This produces a C-specific build + * Return a command to build the specified C file using CMake. This produces a + * C-specific build * command. * - *

Note: It appears that configuration and build cannot happen in one command. Therefore, this + *

+ * Note: It appears that configuration and build cannot happen in one command. + * Therefore, this * is separated into a compile command and a build command. */ public LFCommand buildCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); String cores = String.valueOf(Runtime.getRuntime().availableProcessors()); - LFCommand command = - commandFactory.createCommand( - "cmake", - List.of( - "--build", - ".", - "--target", - "install", - "--parallel", - cores, - "--config", - buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), - buildPath); + LFCommand command = commandFactory.createCommand( + "cmake", + List.of( + "--build", + ".", + "--target", + "install", + "--parallel", + cores, + "--config", + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), + buildPath); if (command == null) { messageReporter .nowhere() @@ -307,8 +313,10 @@ public LFCommand buildCmakeCommand() { } /** - * Return a flash/emulate command using west. If board is null (defaults to qemu_cortex_m3) or - * qemu_* Return a flash command which runs the target as an emulation If ordinary target, return + * Return a flash/emulate command using west. If board is null (defaults to + * qemu_cortex_m3) or + * qemu_* Return a flash command which runs the target as an emulation If + * ordinary target, return * {@code west flash} */ public LFCommand buildWestFlashCommand(PlatformOptions options) { @@ -330,18 +338,23 @@ public LFCommand buildWestFlashCommand(PlatformOptions options) { } /** - * Check if the output produced by CMake has any known and common errors. If a known error is + * Check if the output produced by CMake has any known and common errors. If a + * known error is * detected, a specialized, more informative message is shown. * - *

Errors currently detected: + *

+ * Errors currently detected: * *

    - *
  • C++ compiler used to compile C files: This error shows up as '#error "The - * CMAKE_C_COMPILER is set to a C++ compiler"' in the 'CMakeOutput' string. + *
  • C++ compiler used to compile C files: This error shows up as '#error + * "The + * CMAKE_C_COMPILER is set to a C++ compiler"' in the + * 'CMakeOutput' string. *
* * @param CMakeOutput The captured output from CMake. - * @return true if the provided 'CMakeOutput' contains a known error. false otherwise. + * @return true if the provided 'CMakeOutput' contains a known error. false + * otherwise. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { @@ -371,8 +384,10 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { * Produces the filename including the target-specific extension * * @param fileName The base name of the file without any extensions - * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the compiler produces - * .cpp files instead of .c files and uses a C++ compiler to compiler the code. + * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the + * compiler produces + * .cpp files instead of .c files and uses a C++ compiler to + * compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { return fileName + getFileExtension(cppMode, targetConfig); @@ -381,8 +396,9 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t /** * Return the file extension of the output source files. * - * @param cppMode Whether we are building C code using a C++ compiler. - * @param targetConfig The target configuration that parameterizes the build process. + * @param cppMode Whether we are building C code using a C++ compiler. + * @param targetConfig The target configuration that parameterizes the build + * process. */ static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { From b08a78ae88a518b491777ebc1c0929e7f84b145d Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Mon, 2 Dec 2024 11:49:00 -0800 Subject: [PATCH 49/68] Removed lf_get_federates_bin_directory. Use LF_FED_PACKAGE_DIRECTORY --- .../federated/extensions/CExtension.java | 2 +- .../federated/extensions/CExtensionUtils.java | 159 ++++++++++-------- .../org/lflang/generator/c/CCompiler.java | 3 +- .../transient/TransientDownstreamWithTimer.lf | 6 +- .../TransientDownstreamWithTwoUpstream.lf | 5 +- .../federated/transient/TransientHotSwap.lf | 5 +- .../transient/TransientStatePersistence.lf | 5 +- 7 files changed, 102 insertions(+), 83 deletions(-) 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 e569237629..0529fbecc3 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtension.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtension.java @@ -464,7 +464,7 @@ public String generatePortAbsentReactionBody( + receivingPortID + ", " + connection.getDstFederate().id - + ", (long long) lf_time_logical_elapsed());", + + ", lf_time_logical_elapsed());", "if (" + sendRef + " == NULL || !" + sendRef + "->is_present) {", "LF_PRINT_LOG(\"The output port is NULL or it is not present.\");", " lf_send_port_absent_to_federate(" 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 90cccdcd16..e2fff2f9bf 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) { @@ -104,8 +107,11 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -121,8 +127,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.staToNetworkActionMap.get(federate.staaOffsets.get(i)); + List networkActions = federate.staToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( @@ -155,7 +160,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 @@ -176,15 +182,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. @@ -228,11 +242,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())); } @@ -245,12 +257,14 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { @@ -277,12 +291,14 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -313,10 +329,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(); @@ -325,8 +340,11 @@ public static void generateCMakeInclude( "add_compile_definitions(LF_SOURCE_DIRECTORY=\"" + fileConfig.srcPath + "\")"); cmakeIncludeCode.pr( "add_compile_definitions(LF_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + "\")"); + // After federates have been divided, their root package directory is different. cmakeIncludeCode.pr( - "add_compile_definitions(LF_SOURCE_GEN_DIRECTORY=\"" + fileConfig.getSrcGenPath() + "\")"); + "add_compile_definitions(LF_FED_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + File.separator + + "fed-gen" + File.separator + fileConfig.name + "\")"); + cmakeIncludeCode.pr("add_compile_definitions(LF_FILE_SEPARATOR=\"" + File.separator + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); } @@ -337,7 +355,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 @@ -410,14 +429,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( @@ -474,26 +492,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); } @@ -502,39 +521,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); } @@ -555,7 +576,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/java/org/lflang/generator/c/CCompiler.java b/core/src/main/java/org/lflang/generator/c/CCompiler.java index fb1871d113..13a1f550d8 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -245,8 +245,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f "-DLF_FILE_SEPARATOR='" + quote + separator + quote + "'")); // Add #define for source file directory. // Do not do this for federated programs because for those, the definition is - // put - // into the cmake file (and fileConfig.srcPath is the wrong directory anyway). + // put into the cmake file (and fileConfig.srcPath is the wrong directory anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index b04abd3fd6..9cc8a92c7f 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -13,7 +13,6 @@ target C { preamble {= #include #include - char* lf_get_federates_bin_directory(); const char* lf_get_federation_id(); =} @@ -25,14 +24,15 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc // 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(), + "%s/bin/federate__%s -i %s", + LF_FED_PACKAGE_DIRECTORY, self->fed_instance_name, lf_get_federation_id() ); lf_print("Launching federate federate__%s at physical time " PRINTF_TIME ".", self->fed_instance_name, lf_time_physical()); + lf_print("**** Launch command: %s", mid_launch_cmd); int status = system(mid_launch_cmd); diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 8ccd6db787..7f7791d56f 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -19,7 +19,6 @@ import Middle from "TransientDownstreamWithTimer.lf" preamble {= #include #include - char* lf_get_federates_bin_directory(); const char* lf_get_federation_id(); =} @@ -31,8 +30,8 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc // 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(), + "%s/bin/federate__%s -i %s", + LF_FED_PACKAGE_DIRECTORY, self->fed_instance_name, lf_get_federation_id() ); diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index d0dbf3afbd..42407dcb9a 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -18,7 +18,6 @@ import Down from "TransientDownstreamWithTimer.lf" preamble {= #include #include - char* lf_get_federates_bin_directory(); const char* lf_get_federation_id(); =} @@ -30,8 +29,8 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc // 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(), + "%s/bin/federate__%s -i %s", + LF_FED_PACKAGE_DIRECTORY, self->fed_instance_name, lf_get_federation_id() ); diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 5d4a7f600f..a10a1430e8 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -14,7 +14,6 @@ preamble {= #include #include - char* lf_get_federates_bin_directory(); const char* lf_get_federation_id(); // The internal federate state to be persistent across executions @@ -32,8 +31,8 @@ reactor TransientExec(launch_time: time = 0, fed_instance_name: char* = "instanc // 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(), + "%s/bin/federate__%s -i %s", + LF_FED_PACKAGE_DIRECTORY, self->fed_instance_name, lf_get_federation_id() ); From 58ca5b15e7fe847e51b06337ca2c47175c8b5ba2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 4 Dec 2024 14:40:16 +0100 Subject: [PATCH 50/68] Debugging state persistence in CI --- test/C/src/federated/transient/TransientStatePersistence.lf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index a10a1430e8..d8faba26ab 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -7,7 +7,8 @@ * important. */ target C { - timeout: 2900 ms + timeout: 2900 ms, + logging: LOG } preamble {= From 7d68906181f62abddb404f09b8c056311b355542 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 4 Dec 2024 15:52:24 +0100 Subject: [PATCH 51/68] More output in State Persistence test + Apply Spotless --- .../federated/extensions/CExtensionUtils.java | 9 +- .../org/lflang/generator/c/CCompiler.java | 88 ++++++++----------- .../transient/TransientStatePersistence.lf | 20 +++-- 3 files changed, 57 insertions(+), 60 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 e2fff2f9bf..13da964708 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -342,8 +342,13 @@ public static void generateCMakeInclude( "add_compile_definitions(LF_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + "\")"); // After federates have been divided, their root package directory is different. cmakeIncludeCode.pr( - "add_compile_definitions(LF_FED_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + File.separator - + "fed-gen" + File.separator + fileConfig.name + "\")"); + "add_compile_definitions(LF_FED_PACKAGE_DIRECTORY=\"" + + fileConfig.srcPkgPath + + File.separator + + "fed-gen" + + File.separator + + fileConfig.name + + "\")"); cmakeIncludeCode.pr("add_compile_definitions(LF_FILE_SEPARATOR=\"" + File.separator + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); 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 13a1f550d8..ddd5daebf1 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -49,8 +49,7 @@ import org.lflang.util.LFCommand; /** - * Responsible for creating and executing the necessary CMake command to compile - * code that is + * Responsible for creating and executing the necessary CMake command to compile code that is * generated by the CGenerator. This class uses CMake to compile. * * @author Soroush Bateni @@ -67,8 +66,7 @@ public class CCompiler { MessageReporter messageReporter; /** - * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler - * produces .cpp files + * Indicate whether the compiler is in C++ mode. In C++ mode, the compiler produces .cpp files * instead of .c files and uses a C++ compiler to compiler the code. */ private final boolean cppMode; @@ -79,11 +77,10 @@ public class CCompiler { /** * Create an instance of CCompiler. * - * @param targetConfig The current target configuration. - * @param fileConfig The current file configuration. + * @param targetConfig The current target configuration. + * @param fileConfig The current file configuration. * @param messageReporter Used to report errors. - * @param cppMode Whether the generated code should be compiled as if it - * were C++. + * @param cppMode Whether the generated code should be compiled as if it were C++. */ public CCompiler( TargetConfig targetConfig, @@ -100,9 +97,8 @@ public CCompiler( /** * Run the C compiler by invoking cmake and make. * - * @param generator An instance of GeneratorBase, only used to report error line - * numbers in the - * Eclipse IDE. + * @param generator An instance of GeneratorBase, only used to report error line numbers in the + * Eclipse IDE. * @return true if compilation succeeds, false otherwise. */ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) @@ -197,15 +193,15 @@ public boolean runCCompiler(GeneratorBase generator, LFGeneratorContext context) } /** - * Return a command to compile the specified C file using CMake. This produces a - * C-specific + * Return a command to compile the specified C file using CMake. This produces a C-specific * compile command. */ public LFCommand compileCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); - LFCommand command = commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); + LFCommand command = + commandFactory.createCommand("cmake", cmakeOptions(targetConfig, fileConfig), buildPath); if (command == null) { messageReporter .nowhere() @@ -275,31 +271,29 @@ private String buildTypeToCmakeConfig(BuildType type) { } /** - * Return a command to build the specified C file using CMake. This produces a - * C-specific build + * Return a command to build the specified C file using CMake. This produces a C-specific build * command. * - *

- * Note: It appears that configuration and build cannot happen in one command. - * Therefore, this + *

Note: It appears that configuration and build cannot happen in one command. Therefore, this * is separated into a compile command and a build command. */ public LFCommand buildCmakeCommand() { // Set the build directory to be "build" Path buildPath = fileConfig.getSrcGenPath().resolve("build"); String cores = String.valueOf(Runtime.getRuntime().availableProcessors()); - LFCommand command = commandFactory.createCommand( - "cmake", - List.of( - "--build", - ".", - "--target", - "install", - "--parallel", - cores, - "--config", - buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), - buildPath); + LFCommand command = + commandFactory.createCommand( + "cmake", + List.of( + "--build", + ".", + "--target", + "install", + "--parallel", + cores, + "--config", + buildTypeToCmakeConfig(targetConfig.get(BuildTypeProperty.INSTANCE))), + buildPath); if (command == null) { messageReporter .nowhere() @@ -312,10 +306,8 @@ public LFCommand buildCmakeCommand() { } /** - * Return a flash/emulate command using west. If board is null (defaults to - * qemu_cortex_m3) or - * qemu_* Return a flash command which runs the target as an emulation If - * ordinary target, return + * Return a flash/emulate command using west. If board is null (defaults to qemu_cortex_m3) or + * qemu_* Return a flash command which runs the target as an emulation If ordinary target, return * {@code west flash} */ public LFCommand buildWestFlashCommand(PlatformOptions options) { @@ -337,23 +329,18 @@ public LFCommand buildWestFlashCommand(PlatformOptions options) { } /** - * Check if the output produced by CMake has any known and common errors. If a - * known error is + * Check if the output produced by CMake has any known and common errors. If a known error is * detected, a specialized, more informative message is shown. * - *

- * Errors currently detected: + *

Errors currently detected: * *

    - *
  • C++ compiler used to compile C files: This error shows up as '#error - * "The - * CMAKE_C_COMPILER is set to a C++ compiler"' in the - * 'CMakeOutput' string. + *
  • C++ compiler used to compile C files: This error shows up as '#error "The + * CMAKE_C_COMPILER is set to a C++ compiler"' in the 'CMakeOutput' string. *
* * @param CMakeOutput The captured output from CMake. - * @return true if the provided 'CMakeOutput' contains a known error. false - * otherwise. + * @return true if the provided 'CMakeOutput' contains a known error. false otherwise. */ @SuppressWarnings("BooleanMethodIsAlwaysInverted") private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { @@ -383,10 +370,8 @@ private boolean outputContainsKnownCMakeErrors(String CMakeOutput) { * Produces the filename including the target-specific extension * * @param fileName The base name of the file without any extensions - * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the - * compiler produces - * .cpp files instead of .c files and uses a C++ compiler to - * compiler the code. + * @param cppMode Indicate whether the compiler is in C++ mode In C++ mode, the compiler produces + * .cpp files instead of .c files and uses a C++ compiler to compiler the code. */ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig targetConfig) { return fileName + getFileExtension(cppMode, targetConfig); @@ -395,9 +380,8 @@ static String getTargetFileName(String fileName, boolean cppMode, TargetConfig t /** * Return the file extension of the output source files. * - * @param cppMode Whether we are building C code using a C++ compiler. - * @param targetConfig The target configuration that parameterizes the build - * process. + * @param cppMode Whether we are building C code using a C++ compiler. + * @param targetConfig The target configuration that parameterizes the build process. */ static String getFileExtension(boolean cppMode, TargetConfig targetConfig) { if (targetConfig.getOrDefault(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO) { diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index d8faba26ab..d75079488e 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -64,6 +64,8 @@ reactor Persistence { reaction(in_middle_join) -> out_to_middle {= if (!self->middle_first_join) { lf_set(out_to_middle, self->middle_state); + lf_print("Notifying Mid of the latest state: {%c,%d}", self->middle_state.state_char, + self->middle_state.state_count); } self->middle_first_join = false; =} @@ -71,6 +73,8 @@ reactor Persistence { 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; + lf_print("Latest recieved state: {%c,%d}", self->middle_state.state_char, + self->middle_state.state_count); =} } @@ -111,6 +115,10 @@ reactor Middle { reaction(in_from_persistence) {= self->middle_state = in_from_persistence->value; + lf_print("Recieved the latest state of: {%c,%d} at " PRINTF_TIME ".", + self->middle_state.state_char, + self->middle_state.state_count, + lf_time_logical_elapsed()); =} // When an input is received, the internal state is updated, and then sent to @@ -149,17 +157,17 @@ reactor Down { 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 {= + reaction(in) {= + self->count_in_mid_reactions++; + lf_print("Down in %d", self->count_in_mid_reactions); + =} + + reaction(shutdown) {= if(self->count_join == 2 && in->value < 4) { 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.", From 84a96c3506dbdf42e7e67a672500950b5ba9b106 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 5 Dec 2024 08:50:34 +0100 Subject: [PATCH 52/68] Fix error in TransientStatePersistence --- test/C/src/federated/transient/TransientStatePersistence.lf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index d75079488e..791c3a5ae4 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -168,10 +168,10 @@ reactor Down { =} reaction(shutdown) {= - if(self->count_join == 2 && in->value < 4) { + if(self->count_join == 2 && self->count_in_mid_reactions < 4) { 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, + self->count_in_mid_reactions, 4); } =} From 9212264f4d3487e6daa71b0ad99f93be48d8b4db Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 5 Dec 2024 10:16:41 +0100 Subject: [PATCH 53/68] Avoid name tangling when running CCPP tests --- .../transient/TransientDownstreamWithTimer.lf | 8 +++++++ .../TransientDownstreamWithTwoUpstream.lf | 8 +++++++ .../federated/transient/TransientHotSwap.lf | 8 +++++++ .../transient/TransientStatePersistence.lf | 22 +++++++++++++------ 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index 9cc8a92c7f..aaa99718d1 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -13,7 +13,15 @@ target C { preamble {= #include #include + #ifdef __cplusplus + extern "C" { + #endif + const char* lf_get_federation_id(); + + #ifdef __cplusplus + } + #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 7f7791d56f..a3f8c92754 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -19,7 +19,15 @@ import Middle from "TransientDownstreamWithTimer.lf" preamble {= #include #include + #ifdef __cplusplus + extern "C" { + #endif + const char* lf_get_federation_id(); + + #ifdef __cplusplus + } + #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 42407dcb9a..99ee3a428c 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -18,7 +18,15 @@ import Down from "TransientDownstreamWithTimer.lf" preamble {= #include #include + #ifdef __cplusplus + extern "C" { + #endif + const char* lf_get_federation_id(); + + #ifdef __cplusplus + } + #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index 791c3a5ae4..dec13301c7 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -12,16 +12,24 @@ target C { } preamble {= - #include - #include + #include + #include + + #ifdef __cplusplus + extern "C" { + #endif const char* lf_get_federation_id(); - // The internal federate state to be persistent across executions - typedef struct federate_state_t { - char state_char; - int state_count; - } federate_state_t; + #ifdef __cplusplus + } + #endif + + // 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 */ From 418afdbde153937613e451cc261fee89bcd31c1b Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 5 Dec 2024 14:51:55 +0100 Subject: [PATCH 54/68] Try refactoring TransientStatePersistence test --- .../transient/TransientStatePersistence.lf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index dec13301c7..e22c1e6b3e 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -121,14 +121,6 @@ reactor Middle { lf_set(join, true); =} - reaction(in_from_persistence) {= - self->middle_state = in_from_persistence->value; - lf_print("Recieved the latest state of: {%c,%d} at " PRINTF_TIME ".", - self->middle_state.state_char, - self->middle_state.state_count, - lf_time_logical_elapsed()); - =} - // When an input is received, the internal state is updated, and then sent to // Persistance. reaction(in) -> out, out_to_persistence {= @@ -144,6 +136,14 @@ reactor Middle { lf_stop(); } =} + + reaction(in_from_persistence) {= + self->middle_state = in_from_persistence->value; + lf_print("Recieved the latest state of: {%c,%d} at " PRINTF_TIME ".", + self->middle_state.state_char, + self->middle_state.state_count, + lf_time_logical_elapsed()); + =} } /** From 6a943a5b088e3a86baad613947fc9a7134b48ffc Mon Sep 17 00:00:00 2001 From: "Edward A. Lee" Date: Sun, 8 Dec 2024 15:24:20 -0800 Subject: [PATCH 55/68] Cleaned up lf_get_federation_id --- .../transient/TransientDownstreamWithTimer.lf | 9 ------- .../TransientDownstreamWithTwoUpstream.lf | 9 ------- .../federated/transient/TransientHotSwap.lf | 9 ------- .../transient/TransientStatePersistence.lf | 25 +++++-------------- 4 files changed, 6 insertions(+), 46 deletions(-) diff --git a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf index aaa99718d1..cdac2d994c 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -13,15 +13,6 @@ target C { preamble {= #include #include - #ifdef __cplusplus - extern "C" { - #endif - - const char* lf_get_federation_id(); - - #ifdef __cplusplus - } - #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index a3f8c92754..44395f244f 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -19,15 +19,6 @@ import Middle from "TransientDownstreamWithTimer.lf" preamble {= #include #include - #ifdef __cplusplus - extern "C" { - #endif - - const char* lf_get_federation_id(); - - #ifdef __cplusplus - } - #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientHotSwap.lf b/test/C/src/federated/transient/TransientHotSwap.lf index 99ee3a428c..b8270af8d7 100644 --- a/test/C/src/federated/transient/TransientHotSwap.lf +++ b/test/C/src/federated/transient/TransientHotSwap.lf @@ -18,15 +18,6 @@ import Down from "TransientDownstreamWithTimer.lf" preamble {= #include #include - #ifdef __cplusplus - extern "C" { - #endif - - const char* lf_get_federation_id(); - - #ifdef __cplusplus - } - #endif =} /** Persistent federate that is responsible for lauching the transient federate */ diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index e22c1e6b3e..d7b28382df 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -1,30 +1,17 @@ /** * 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. + * joins. Whenever the state (of type `federate_state_t`) changes, it notifies `Persistence`. `Middle` + * notifies `Persistence` also when it joins. When `Middle` 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: 2900 ms, - logging: LOG + timeout: 2900 ms } preamble {= #include #include - - #ifdef __cplusplus - extern "C" { - #endif - - const char* lf_get_federation_id(); - - #ifdef __cplusplus - } - #endif - // The internal federate state to be persistent across executions typedef struct federate_state_t { char state_char; @@ -81,7 +68,7 @@ reactor Persistence { 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; - lf_print("Latest recieved state: {%c,%d}", self->middle_state.state_char, + lf_print("Latest received state: {%c,%d}", self->middle_state.state_char, self->middle_state.state_count); =} } @@ -139,7 +126,7 @@ reactor Middle { reaction(in_from_persistence) {= self->middle_state = in_from_persistence->value; - lf_print("Recieved the latest state of: {%c,%d} at " PRINTF_TIME ".", + lf_print("Received the latest state of: {%c,%d} at " PRINTF_TIME ".", self->middle_state.state_char, self->middle_state.state_count, lf_time_logical_elapsed()); From 8da5c8ac893e0fdb36fa1d3339b4a3b971a034bf Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 9 Dec 2024 13:09:16 +0100 Subject: [PATCH 56/68] Fix messages order in TransientStatePersistence test + format + align reactor-c --- .../transient/TransientStatePersistence.lf | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/test/C/src/federated/transient/TransientStatePersistence.lf b/test/C/src/federated/transient/TransientStatePersistence.lf index d7b28382df..bb5c0eff68 100644 --- a/test/C/src/federated/transient/TransientStatePersistence.lf +++ b/test/C/src/federated/transient/TransientStatePersistence.lf @@ -1,22 +1,22 @@ /** * 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 (of type `federate_state_t`) changes, it notifies `Persistence`. `Middle` - * notifies `Persistence` also when it joins. When `Middle` joins the second time or after, it receives - * the saved state and sets it. In this, the order of the reactions is important. + * joins. Whenever the state (of type `federate_state_t`) changes, it notifies `Persistence`. + * `Middle` notifies `Persistence` also when it joins. When `Middle` 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: 2900 ms } 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; + #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 */ @@ -108,6 +108,14 @@ reactor Middle { lf_set(join, true); =} + reaction(in_from_persistence) {= + self->middle_state = in_from_persistence->value; + lf_print("Received the latest state of: {%c,%d} at " PRINTF_TIME ".", + self->middle_state.state_char, + self->middle_state.state_count, + lf_time_logical_elapsed()); + =} + // When an input is received, the internal state is updated, and then sent to // Persistance. reaction(in) -> out, out_to_persistence {= @@ -123,14 +131,6 @@ reactor Middle { lf_stop(); } =} - - reaction(in_from_persistence) {= - self->middle_state = in_from_persistence->value; - lf_print("Received the latest state of: {%c,%d} at " PRINTF_TIME ".", - self->middle_state.state_char, - self->middle_state.state_count, - lf_time_logical_elapsed()); - =} } /** From 961f0a4f43cf730555cddb0c33d4d9229be3a7f5 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Wed, 11 Dec 2024 22:54:33 +0100 Subject: [PATCH 57/68] Better logical ordering of the reactions in transients tests + align reactor-c --- .../federated/transient/TransientDownstreamWithTimer.lf | 8 ++++---- .../transient/TransientDownstreamWithTwoUpstream.lf | 8 ++++---- 2 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 cdac2d994c..0b9626a362 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTimer.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTimer.lf @@ -111,14 +111,14 @@ reactor Down { self->count_timer++; =} - reaction(in) {= - self->count_in_mid_reactions++; - =} - reaction(join) {= self->count_join++; =} + reaction(in) {= + self->count_in_mid_reactions++; + =} + reaction(shutdown) {= // Check that the TAG has been successfully issued to Down if (self->count_timer < 5) { diff --git a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf index 44395f244f..745ee2727d 100644 --- a/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf +++ b/test/C/src/federated/transient/TransientDownstreamWithTwoUpstream.lf @@ -69,6 +69,10 @@ reactor Down { self->count_timer++; =} + reaction(join) {= + self->count_join++; + =} + reaction(in_mid) {= self->count_in_mid_reactions++; =} @@ -77,10 +81,6 @@ reactor Down { 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) { From ff68011c8ce13864fc5823566a1c9ce50423daeb Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Fri, 3 Jan 2025 12:13:44 +0100 Subject: [PATCH 58/68] Cleanup after rebase --- .../federated/extensions/CExtensionUtils.java | 170 ++++++++---------- core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 73 insertions(+), 99 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 13da964708..a7eeda782a 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -36,20 +36,17 @@ 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) { @@ -78,17 +75,11 @@ public static String initializeTriggersForNetworkActions( // Set the ID of the source federate. code.pr( trigger + ".source_id = " + federate.networkMessageSourceFederate.get(i).id + "; \\"); - if (federate.zeroDelayCycleNetworkMessageActions.contains(action)) { - for (int j = 0; j < federate.zeroDelayCycleNetworkUpstreamFeds.size(); ++j) { - var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(j); - code.pr( - "_lf_zero_delay_cycle_upstream_ids[" - + zeroDelayActionTableCount - + "] = " - + upstream.id - + "; \\"); - } - if (federate.isTransient) { + int j = federate.zeroDelayCycleNetworkMessageActions.indexOf(action); + if (j >= 0) { + var upstream = federate.zeroDelayCycleNetworkUpstreamFeds.get(j); + code.pr("_lf_zero_delay_cycle_upstream_ids[" + j + "] = " + upstream.id + "; \\"); + if (upstream.isTransient) { // Transient federates are assumed to be initially disconnected. code.pr("_lf_zero_delay_cycle_upstream_disconnected[" + j + "] = true; \\"); } @@ -107,11 +98,8 @@ public static String initializeTriggersForNetworkActions( /** * Generate C code that holds a sorted list of STAA 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. @@ -127,7 +115,8 @@ 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.staToNetworkActionMap.get(federate.staaOffsets.get(i)); + List networkActions = + federate.staToNetworkActionMap.get(federate.staaOffsets.get(i)); code.pr("staa_lst[" + i + "] = (staa_t*) malloc(sizeof(staa_t));"); code.pr( @@ -160,8 +149,7 @@ 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 @@ -182,23 +170,15 @@ 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. @@ -242,9 +222,11 @@ 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())); } @@ -257,14 +239,12 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void initializeClockSynchronization( FederateInstance federate, RtiConfig rtiConfig, MessageReporter messageReporter) { @@ -291,14 +271,12 @@ 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 + * "https://github.com/icyphy/lingua-franca/wiki/Distributed-Execution#clock-synchronization">Documentation */ public static void addClockSyncCompileDefinitions(FederateInstance federate) { @@ -329,9 +307,10 @@ 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(); @@ -360,8 +339,7 @@ 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 @@ -434,13 +412,14 @@ 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( @@ -497,27 +476,26 @@ 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); } @@ -526,41 +504,39 @@ 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); } @@ -581,9 +557,7 @@ 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 fe03b3f0e6..09d31fe0dd 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit fe03b3f0e6ecdf201d5323a341a2ab7e82a2818a +Subproject commit 09d31fe0ddd87ae2dc9326fb2fa4b3f402737d89 From 93b571969da548cce98cbd42784704a7bb11fe16 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Fri, 3 Jan 2025 16:18:08 +0100 Subject: [PATCH 59/68] Aligne 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 09d31fe0dd..6893de6064 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 09d31fe0ddd87ae2dc9326fb2fa4b3f402737d89 +Subproject commit 6893de6064a01f049abe09ceacb02b843c89ae42 From 322bc2bf6c5dcb6ade2d548ab09506fa46af9a91 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 4 Jan 2025 11:56:30 +0100 Subject: [PATCH 60/68] Align reactr-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 6893de6064..bbba28549d 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 6893de6064a01f049abe09ceacb02b843c89ae42 +Subproject commit bbba28549d38f7d206fd8f2d77cedfe32a264dbe From 4e33e86683095f2fd99b2eb69ac349be2b4ac7bd Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 4 Jan 2025 17:14:20 +0100 Subject: [PATCH 61/68] 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 98ccd3b3e1..95e67b6290 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 98ccd3b3e131ebbe728a2329a02b64a1efc52b15 +Subproject commit 95e67b6290f76e2a9eec62f33434ab2d2a5ef03e From 141a4209bf4a76569ca59dff37b31146389bd6ec Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 4 Jan 2025 20:47:46 +0100 Subject: [PATCH 62/68] 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 95e67b6290..7727215ce6 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 95e67b6290f76e2a9eec62f33434ab2d2a5ef03e +Subproject commit 7727215ce60a0759ceaf55c1cb0cda6ed66fd78c From ea39b50f2a0f7b5db5c86d0d733f45a0457f7a8b Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sat, 4 Jan 2025 22:52:22 +0100 Subject: [PATCH 63/68] 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 7727215ce6..9be359694b 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 7727215ce60a0759ceaf55c1cb0cda6ed66fd78c +Subproject commit 9be359694b19e51ce374dd7b6fa95a84be48ef47 From 779df68e67f78dd4ef83665bed587790c39c33c2 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Sun, 5 Jan 2025 01:30:54 +0100 Subject: [PATCH 64/68] 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 9be359694b..e106ea11b9 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 9be359694b19e51ce374dd7b6fa95a84be48ef47 +Subproject commit e106ea11b99ea46caa63acb6a9532cc450e60ddd From b19c602516f086563980e9809a27758b9ea5c6f7 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Mon, 13 Jan 2025 15:56:10 +0100 Subject: [PATCH 65/68] Fix adding LF_SOURCE_GEN_DIRECTORY flag to cmake --- core/src/main/java/org/lflang/generator/c/CCompiler.java | 6 +++--- core/src/main/resources/lib/c/reactor-c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) 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 ddd5daebf1..5c1defff83 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -241,14 +241,14 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f "-DLF_FILE_SEPARATOR='" + quote + separator + quote + "'")); // Add #define for source file directory. // Do not do this for federated programs because for those, the definition is - // put into the cmake file (and fileConfig.srcPath is the wrong directory anyway). + // put into the cmake file (and fileConfig.srcPath is the wrong directory + // anyway). if (!fileConfig.srcPath.toString().contains("fed-gen")) { // Do not convert to Unix path arguments.add("-DLF_SOURCE_DIRECTORY='" + quote + srcPath + quote + "'"); arguments.add("-DLF_PACKAGE_DIRECTORY='" + quote + rootPath + quote + "'"); - } else { - arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); } + arguments.add("-DLF_SOURCE_GEN_DIRECTORY='" + quote + srcGenPath + quote + "'"); arguments.add(FileUtil.toUnixString(fileConfig.getSrcGenPath())); if (GeneratorUtils.isHostWindows()) { diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index e106ea11b9..ea2c3ab7b2 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit e106ea11b99ea46caa63acb6a9532cc450e60ddd +Subproject commit ea2c3ab7b252e0a2f46561a3fd0a627a7d26bb29 From b567efe3f2be432d51b87a0b1b6f7d8267361a2f Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Thu, 23 Jan 2025 20:11:43 +0100 Subject: [PATCH 66/68] Align reactor-cpp --- core/src/main/resources/lib/cpp/reactor-cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/cpp/reactor-cpp b/core/src/main/resources/lib/cpp/reactor-cpp index d009fdd85b..d255a3da57 160000 --- a/core/src/main/resources/lib/cpp/reactor-cpp +++ b/core/src/main/resources/lib/cpp/reactor-cpp @@ -1 +1 @@ -Subproject commit d009fdd85bf15beb992a3102a99ed91497f8a6fd +Subproject commit d255a3da57d38db2988bcab68024b0a77ccc8657 From fc44ae5a0fe6bd103c552c6c3c4f01d8d7a6ba6e Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Fri, 31 Jan 2025 06:53:34 +0100 Subject: [PATCH 67/68] 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 c0223177b6..57ba24d07c 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit c0223177b6e6f7d181e26623f50ae91c2d56f947 +Subproject commit 57ba24d07c7dfaf33dd837395caf340a247b552a From aadc9283d000c2e92db9eaf5312f4adafb491c90 Mon Sep 17 00:00:00 2001 From: Chadlia Jerad Date: Fri, 31 Jan 2025 07:28:47 +0100 Subject: [PATCH 68/68] 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 57ba24d07c..7e2971ba3a 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 57ba24d07c7dfaf33dd837395caf340a247b552a +Subproject commit 7e2971ba3a2f1d4820efccd3108faef589237f84