diff --git a/.github/scripts/run-zephyr-tests.sh b/.github/scripts/run-zephyr-tests.sh index 20dddda94c..d1c1d1c4e9 100755 --- a/.github/scripts/run-zephyr-tests.sh +++ b/.github/scripts/run-zephyr-tests.sh @@ -1,15 +1,7 @@ #!/bin/bash -timeout=300 # 5min timeout is hopefully enough -verbose=false -# Function to recursively find all folders containing the top-level CMakeLists.txt -overall_success=true -num_successes=0 -num_failures=0 -failed_tests="" - -# Skip tests doing file IO and tracing -skip=("FileReader" "FilePkgReader" "Tracing" "ThreadedThreaded" "CountTest" "AsyncCallback") +# Skip +skip=("FileReader" "FilePkgReader") find_kconfig_folders() { if [ -f "$folder/CMakeLists.txt" ]; then @@ -20,17 +12,15 @@ find_kconfig_folders() { echo "Skipping: $test_name" else echo "Running: $test_name" - if run_qemu_zephyr_test "$folder"; then - echo "Test $test_name successful" + run_qemu_zephyr_test $folder + if [ "$?" -eq 0 ]; then + echo "Test passed" let "num_successes+=1" else - echo "Test $test_name failed" - let "num_failures+=1" - failed_tests+="$test_name, " - overall_success=false + echo "Test failed." + exit 1 fi fi - return fi for folder in "$1"/*; do @@ -40,88 +30,55 @@ find_kconfig_folders() { done } -run_native_zephyr_test() { - return_val=0 - pushd $1/build - - rm -f res.text - - timeout 60s make run | tee res.txt - result=$? - - if [ $result -eq 0 ]; then - echo "Command completed within the timeout." - return_val=0 - else - echo "Command terminated or timed out." - echo "Test output:" - echo "----------------------------------------------------------------" - cat res.txt - echo "----------------------------------------------------------------" - return_val=1 - fi - - popd - return "$return_val" - - - - -} - -# Run Zephyr test until either: Timeout or finds match in output -# https://www.unix.com/shell-programming-and-scripting/171401-kill-process-if-grep-match-found.html +# Run Zephyr test until either: Timeout or finds match in output using expect +# https://spin.atomicobject.com/monitoring-stdout-with-a-timeout/ run_qemu_zephyr_test() { success=false pushd $1/build - - rm -f /tmp/procfifo - rm -f res.text - mkfifo /tmp/procfifo - - make run | tee res.txt > /tmp/procfifo & - PID=$! - SECONDS=0 - while IFS= read -t $timeout line - do - if [ "$verbose" = "true" ]; then echo $line; fi - - if echo "$line" | grep -q 'FATAL ERROR'; + res="_res.txt" + # Run test program in background and pipe results to a file. + make run > $res & + if [ $? -ne 0 ]; then + echo "ERROR: make run failed." + exit 1 + fi + pid=$! + return_val=2 + wait_count=0 + timeout=60 + # Parse the file and match on known outputs. With timeout. + while [ "$wait_count" -le "$timeout" ]; do + sleep 1 + if grep --quiet 'FATAL ERROR' "$res" then - echo "Matched on ERROR" - echo $line - success=false - pkill -P $$ + cat $res + echo "-----------------------------------------------------------------------------------------------------------" + echo "ERROR: Found 'FATAL ERROR'" + return_val=1 break fi - - if echo "$line" | grep -q '^exit'; + if grep --quiet '^exit' "$res" then - echo "Matched on exit" - success=true - pkill -P $$ - break - fi - - if (($SECONDS > $timeout)) ; then - echo "Timeout without freeze" - success=false + cat $res + echo "-----------------------------------------------------------------------------------------------------------" + echo "SUCCESS: Found 'exit'" + return_val=0 break fi - done < /tmp/procfifo - return_val=0 - if [ "$success" = false ]; then - echo "General Timeout" - pkill -P $$ - echo "Test output:" - echo "----------------------------------------------------------------" - cat res.txt - echo "----------------------------------------------------------------" - return_val=1 + ((wait_count++)) + done + kill $pid + if [ $? -ne 0 ]; then + echo "ERROR: Could not kill qemu process" + exit 1 fi - rm -f /tmp/procfifo + if [ "$return_val" -eq 2 ]; then + cat $res + echo "-----------------------------------------------------------------------------------------------------------" + echo "ERROR: Timed out" + fi popd return "$return_val" } @@ -137,14 +94,8 @@ cd - # Print report echo "================================================================================================================" - -if [ "$overall_success" = false ]; then - echo "Results: FAIL" -else - echo "Results: PASS" -fi +echo "Tests passed!" echo "Number of passes: $num_successes" -echo "Number of fails: $num_failures" echo "Skipped tests: ${skip[@]}" if [ "$overall_success" = false ]; then diff --git a/.github/workflows/custom-build.yml b/.github/workflows/custom-build.yml new file mode 100644 index 0000000000..9f63be882f --- /dev/null +++ b/.github/workflows/custom-build.yml @@ -0,0 +1,43 @@ +name: Custom build + +# Trigger the workflow every day at 5 AM (UTC). +on: + workflow_dispatch: + +jobs: + custom-build: + runs-on: ubuntu-latest + steps: + - name: Check out lingua-franca repository + uses: actions/checkout@v3 + with: + submodules: recursive + fetch-depth: 0 + - name: Prepare build environment + uses: ./.github/actions/prepare-build-env + - name: Modify property file to contain the commit SHA + shell: bash + run: | + TIMESTAMP="$(date +'%Y-%m-%d')" + SHA="$(git rev-parse --short HEAD)" + sed --regexp-extended --in-place "s/^(VERSION = .*)$/\1 ${SHA} ${TIMESTAMP}/" core/src/main/resources/org/lflang/StringsBundle.properties + - name: Build and package lf cli tools (nightly build) + shell: bash + run: | + export TIMESTAMP="$(date +'%Y%m%d%H%M%S')" + echo "timestamp=$TIMESTAMP" >> "$GITHUB_ENV" + ./gradlew build -Pnightly=$TIMESTAMP -PtargetOS=Linux -PtargetArch=x86_64 + ./gradlew assemble -Pnightly=$TIMESTAMP -PtargetOS=Linux -PtargetArch=aarch64 + ./gradlew assemble -Pnightly=$TIMESTAMP -PtargetOS=MacOS -PtargetArch=x86_64 + ./gradlew assemble -Pnightly=$TIMESTAMP -PtargetOS=MacOS -PtargetArch=aarch64 + ./gradlew assemble -Pnightly=$TIMESTAMP -PtargetOS=Windows -PtargetArch=x86_64 + - name: Deploy nightly release + uses: marvinpinto/action-automatic-releases@latest + with: + repo_token: "${{ secrets.NIGHTLY_BUILD }}" + automatic_release_tag: '${{ github.ref_name }}' + prerelease: true + draft: true + title: "Custom Lingua Franca build for ${{ github.ref_name }} branch" + files: | + build/distributions/* diff --git a/core/src/main/java/org/lflang/MessageReporterBase.java b/core/src/main/java/org/lflang/MessageReporterBase.java index edd39d2799..287d47153f 100644 --- a/core/src/main/java/org/lflang/MessageReporterBase.java +++ b/core/src/main/java/org/lflang/MessageReporterBase.java @@ -40,11 +40,17 @@ public Stage2 at(Path file, Range range) { @Override public Stage2 at(EObject node) { + if (node == null) { + return nowhere(); + } return wrap((severity, message) -> reportOnNode(node, severity, message)); } @Override public Stage2 at(EObject node, EStructuralFeature feature) { + if (node == null) { + return nowhere(); + } return wrap((severity, message) -> reportOnNode(node, feature, severity, message)); } 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 fb74f98c1a..4b1fed0afe 100644 --- a/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java +++ b/core/src/main/java/org/lflang/federated/extensions/CExtensionUtils.java @@ -201,6 +201,7 @@ public static void handleCompileDefinitions( } definitions.put("NUMBER_OF_FEDERATES", String.valueOf(numOfFederates)); definitions.put("EXECUTABLE_PREAMBLE", ""); + definitions.put("FEDERATE_ID", String.valueOf(federate.id)); CompileDefinitionsProperty.INSTANCE.update(federate.targetConfig, definitions); @@ -303,7 +304,8 @@ public static void generateCMakeInclude( "add_compile_definitions(LF_SOURCE_DIRECTORY=\"" + fileConfig.srcPath + "\")"); cmakeIncludeCode.pr( "add_compile_definitions(LF_PACKAGE_DIRECTORY=\"" + fileConfig.srcPkgPath + "\")"); - + cmakeIncludeCode.pr( + "add_compile_definitions(LF_SOURCE_GEN_DIRECTORY=\"" + fileConfig.getSrcGenPath() + "\")"); try (var srcWriter = Files.newBufferedWriter(cmakeIncludePath)) { srcWriter.write(cmakeIncludeCode.getCode()); } 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 5ec59ecb34..67cc8085f0 100644 --- a/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java +++ b/core/src/main/java/org/lflang/federated/launcher/FedLauncherGenerator.java @@ -124,7 +124,7 @@ public void doGenerate(List federates, RtiConfig rtiConfig) { target = user + "@" + host; } - shCode.append("#### Host is ").append(host); + shCode.append("#### Host is ").append(host).append("\n"); // Launch the RTI in the foreground. if (host.equals("localhost") || host.equals("0.0.0.0")) { diff --git a/core/src/main/java/org/lflang/generator/CodeBuilder.java b/core/src/main/java/org/lflang/generator/CodeBuilder.java index 9fe82e46fd..af82d70512 100644 --- a/core/src/main/java/org/lflang/generator/CodeBuilder.java +++ b/core/src/main/java/org/lflang/generator/CodeBuilder.java @@ -126,7 +126,8 @@ public void prSourceLineNumber(EObject eObject, boolean suppress) { } } // Extract the filename from eResource, an astonishingly difficult thing to do. - String filePath = CommonPlugin.resolve(eObject.eResource().getURI()).path(); + String filePath = + CommonPlugin.resolve(eObject.eResource().getURI()).path().replace("\\", "\\\\"); pr("#line " + (node.getStartLine() + offset) + " \"" + filePath + "\""); } } @@ -558,7 +559,11 @@ public CodeMap writeToFile(String path) throws IOException { for (var line : (Iterable) () -> s.lines().iterator()) { lineNumber++; if (line.contains(END_SOURCE_LINE_NUMBER_TAG) && !path.endsWith(".ino")) { - out.append("#line ").append(lineNumber).append(" \"").append(path).append("\""); + out.append("#line ") + .append(lineNumber) + .append(" \"") + .append(path.replace("\\", "\\\\")) + .append("\""); } else { out.append(line); } diff --git a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java index 1390fa3ce0..7212e448a4 100644 --- a/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CCmakeGenerator.java @@ -422,6 +422,14 @@ CodeBuilder generateCMakeCode( } cMakeCode.newLine(); + // Add definition of directory where the main CMakeLists.txt file resides because this is where + // any files specified by the `file` target directive will be put. + cMakeCode.pr( + "# Define directory in which files from the 'files' target directive will be put."); + cMakeCode.pr( + "target_compile_definitions(${LF_MAIN_TARGET} PUBLIC" + + " LF_TARGET_FILES_DIRECTORY=\"${CMAKE_CURRENT_LIST_DIR}\")"); + cMakeCode.pr(cMakeExtras); cMakeCode.newLine(); 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 b26e7686e2..c0401b5684 100644 --- a/core/src/main/java/org/lflang/generator/c/CCompiler.java +++ b/core/src/main/java/org/lflang/generator/c/CCompiler.java @@ -42,6 +42,7 @@ import org.lflang.target.property.CompilerProperty; import org.lflang.target.property.PlatformProperty; import org.lflang.target.property.PlatformProperty.PlatformOptions; +import org.lflang.target.property.TracePluginProperty; import org.lflang.target.property.type.BuildTypeType.BuildType; import org.lflang.target.property.type.PlatformType.Platform; import org.lflang.util.FileUtil; @@ -219,11 +220,13 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f String maybeQuote = ""; // Windows seems to require extra level of quoting. String srcPath = fileConfig.srcPath.toString(); // Windows requires escaping the backslashes. String rootPath = fileConfig.srcPkgPath.toString(); + String srcGenPath = fileConfig.getSrcGenPath().toString(); if (separator.equals("\\")) { separator = "\\\\\\\\"; maybeQuote = "\\\""; srcPath = srcPath.replaceAll("\\\\", "\\\\\\\\"); rootPath = rootPath.replaceAll("\\\\", "\\\\\\\\"); + srcGenPath = srcGenPath.replaceAll("\\\\", "\\\\\\\\"); } arguments.addAll( List.of( @@ -235,6 +238,14 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f "-DCMAKE_INSTALL_BINDIR=" + FileUtil.toUnixString(fileConfig.getOutPath().relativize(fileConfig.binPath)), "-DLF_FILE_SEPARATOR=\"" + maybeQuote + separator + maybeQuote + "\"")); + var tracePlugin = targetConfig.getOrDefault(TracePluginProperty.INSTANCE); + if (tracePlugin != null) { + arguments.add( + "-DLF_TRACE_PLUGIN=" + + targetConfig + .getOrDefault(TracePluginProperty.INSTANCE) + .getImplementationArchiveFile()); + } // 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). @@ -242,6 +253,7 @@ private static List cmakeOptions(TargetConfig targetConfig, FileConfig f // 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(FileUtil.toUnixString(fileConfig.getSrcGenPath())); diff --git a/core/src/main/java/org/lflang/generator/c/CConstructorGenerator.java b/core/src/main/java/org/lflang/generator/c/CConstructorGenerator.java index 529e37a975..b18b8bc9a9 100644 --- a/core/src/main/java/org/lflang/generator/c/CConstructorGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CConstructorGenerator.java @@ -16,7 +16,7 @@ public static String generateConstructor(TypeParameterizedReactor tpr, String co code.pr(structType + "* new_" + CUtil.getName(tpr) + "() {"); code.indent(); code.pr( - structType + "* self = (" + structType + "*)_lf_new_reactor(sizeof(" + structType + "));"); + structType + "* self = (" + structType + "*)lf_new_reactor(sizeof(" + structType + "));"); code.pr(constructorCode); code.pr("return self;"); code.unindent(); diff --git a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java index b289a9978f..3789638ded 100644 --- a/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CEnvironmentFunctionGenerator.java @@ -78,7 +78,7 @@ private String generateEnvironmentEnum() { private String generateCreateEnvironments() { CodeBuilder code = new CodeBuilder(); code.pr("// 'Create' and initialize the environments in the program"); - code.pr("void _lf_create_environments() {"); + code.pr("void lf_create_environments() {"); code.indent(); for (ReactorInstance enclave : enclaves) { // Decide the number of workers to use. If this is the top-level diff --git a/core/src/main/java/org/lflang/generator/c/CGenerator.java b/core/src/main/java/org/lflang/generator/c/CGenerator.java index afd2ce53da..86d45f4c48 100644 --- a/core/src/main/java/org/lflang/generator/c/CGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CGenerator.java @@ -630,7 +630,7 @@ private void generateCodeFor(String lfModuleName) throws IOException { code.pr( """ #ifndef FEDERATED - void terminate_execution(environment_t* env) {} + void lf_terminate_execution(environment_t* env) {} #endif"""); } } @@ -869,12 +869,14 @@ private void pickCompilePlatform() { /** Copy target-specific header file to the src-gen directory. */ protected void copyTargetFiles() throws IOException { Path dest = fileConfig.getSrcGenPath(); + var arduino = false; if (targetConfig.isSet(PlatformProperty.INSTANCE)) { var platform = targetConfig.get(PlatformProperty.INSTANCE).platform(); switch (platform) { case ARDUINO -> { // For Arduino, alter the destination directory. dest = dest.resolve("src"); + arduino = true; } case ZEPHYR -> { // For the Zephyr target, copy default config and board files. @@ -903,8 +905,27 @@ protected void copyTargetFiles() throws IOException { Path coreLib = Paths.get(context.getArgs().externalRuntimeUri()); FileUtil.copyDirectoryContents(coreLib, dest, true); } else { - FileUtil.copyFromClassPath("/lib/c/reactor-c/core", dest, true, false); - FileUtil.copyFromClassPath("/lib/c/reactor-c/lib", dest, true, false); + for (var directory : List.of("core", "lib")) { + FileUtil.copyFromClassPath("/lib/c/reactor-c/" + directory, dest, true, false); + } + for (var directory : + List.of("logging", "platform", "low_level_platform", "trace", "version", "tag")) { + var entry = "/lib/c/reactor-c/" + directory; + if (arduino) { + if (FileConfig.class.getResource(entry + "/api") != null) { + FileUtil.copyFromClassPath( + entry + "/api", + fileConfig.getSrcGenPath().resolve("include").resolve(directory), + true, + false); + } + if (FileConfig.class.getResource(entry + "/impl") != null) { + FileUtil.copyFromClassPath(entry + "/impl", dest.resolve(directory), true, false); + } + } else { + FileUtil.copyFromClassPath(entry, dest, true, false); + } + } } } @@ -953,7 +974,11 @@ protected void generateReactorClassHeaders( } header.pr("#include \"include/core/reactor.h\""); src.pr("#include \"include/api/schedule.h\""); - src.pr("#include \"include/core/platform.h\""); + if (CPreambleGenerator.arduinoBased(targetConfig)) { + src.pr("#include \"include/low_level_platform/api/low_level_platform.h\""); + } else { + src.pr("#include \"low_level_platform/api/low_level_platform.h\""); + } generateIncludes(tpr); if (cppMode) { src.pr("}"); @@ -1360,13 +1385,10 @@ private void recordBuiltinTriggers(ReactorInstance instance) { if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { var description = CUtil.getShortenedName(reactor); var reactorRef = CUtil.reactorRef(reactor); - var envTraceRef = CUtil.getEnvironmentStruct(reactor) + ".trace"; temp.pr( String.join( "\n", "_lf_register_trace_event(" - + envTraceRef - + "," + reactorRef + ", &(" + reactorRef diff --git a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java index a1d8cb652c..ba054d6e49 100644 --- a/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CMainFunctionGenerator.java @@ -101,11 +101,11 @@ private String generateSetDefaultCliOption() { + StringUtil.addDoubleQuotes( StringUtil.joinObjects(runCommand, StringUtil.addDoubleQuotes(", "))) + " };", - "void _lf_set_default_command_line_options() {", + "void lf_set_default_command_line_options() {", " default_argc = " + runCommand.size() + ";", " default_argv = _lf_default_argv;", "}") - : "void _lf_set_default_command_line_options() {}"; + : "void lf_set_default_command_line_options() {}"; } /** Parse the target parameters and set flags to the runCommand accordingly. */ diff --git a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java index 44cf25dbd1..56c2d85ff7 100644 --- a/core/src/main/java/org/lflang/generator/c/CPortGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPortGenerator.java @@ -101,7 +101,7 @@ public static String initializeInputMultiport(PortInstance input, String reactor "\n", portRefName + "_width = " + input.getWidth() + ";", "// Allocate memory for multiport inputs.", - portRefName + " = (" + variableStructType(input) + "**)_lf_allocate(", + portRefName + " = (" + variableStructType(input) + "**)lf_allocate(", " " + input.getWidth() + ", sizeof(" + variableStructType(input) + "*),", " &" + reactorSelfStruct + "->base.allocations); ", "// Set inputs by default to an always absent default input.", @@ -119,7 +119,7 @@ public static String initializeInputMultiport(PortInstance input, String reactor "\n", result, "if (" + input.getWidth() + " >= LF_SPARSE_WIDTH_THRESHOLD) {", - " " + portRefName + "__sparse = (lf_sparse_io_record_t*)_lf_allocate(1,", + " " + portRefName + "__sparse = (lf_sparse_io_record_t*)lf_allocate(1,", " sizeof(lf_sparse_io_record_t) + sizeof(size_t) * " + input.getWidth() + "/LF_SPARSE_CAPACITY_DIVIDER,", @@ -158,10 +158,10 @@ public static String initializeOutputMultiport(PortInstance output, String react "\n", portRefName + "_width = " + output.getWidth() + ";", "// Allocate memory for multiport output.", - portRefName + " = (" + portStructType + "*)_lf_allocate(", + portRefName + " = (" + portStructType + "*)lf_allocate(", " " + output.getWidth() + ", sizeof(" + portStructType + "),", " &" + reactorSelfStruct + "->base.allocations); ", - portRefName + "_pointers = (" + portStructType + "**)_lf_allocate(", + portRefName + "_pointers = (" + portStructType + "**)lf_allocate(", " " + output.getWidth() + ", sizeof(" + portStructType + "*),", " &" + reactorSelfStruct + "->base.allocations); ", "// Assign each output port pointer to be used in", diff --git a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java index 080b4c5848..53b35002f4 100644 --- a/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CPreambleGenerator.java @@ -1,7 +1,5 @@ package org.lflang.generator.c; -import static org.lflang.util.StringUtil.addDoubleQuotes; - import java.nio.file.Path; import java.util.HashMap; import org.lflang.generator.CodeBuilder; @@ -32,7 +30,7 @@ */ public class CPreambleGenerator { - private static boolean arduinoBased(TargetConfig targetConfig) { + public static boolean arduinoBased(TargetConfig targetConfig) { return targetConfig.isSet(PlatformProperty.INSTANCE) && targetConfig.get(PlatformProperty.INSTANCE).platform() == Platform.ARDUINO; } @@ -43,7 +41,11 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea code.pr("extern \"C\" {"); } code.pr("#include "); - code.pr("#include \"include/core/platform.h\""); + if (arduinoBased(targetConfig)) { + code.pr("#include \"include/low_level_platform/api/low_level_platform.h\""); + } else { + code.pr("#include \"low_level_platform/api/low_level_platform.h\""); + } CCoreFilesUtils.getCTargetHeader() .forEach(it -> code.pr("#include " + StringUtil.addDoubleQuotes(it))); code.pr("#include \"include/core/reactor.h\""); @@ -53,7 +55,7 @@ public static String generateIncludeStatements(TargetConfig targetConfig, boolea } if (targetConfig.get(TracingProperty.INSTANCE).isEnabled()) { - code.pr("#include \"include/core/trace.h\""); + code.pr("#include \"trace/api/trace.h\""); } code.pr("#include \"include/core/mixed_radix.h\""); code.pr("#include \"include/core/port.h\""); @@ -76,7 +78,6 @@ public static String generateDefineDirectives(TargetConfig targetConfig, Path sr CodeBuilder code = new CodeBuilder(); // TODO: Get rid of all of these code.pr("#define LOG_LEVEL " + logLevel); - code.pr("#define TARGET_FILES_DIRECTORY " + addDoubleQuotes(srcGenPath.toString())); final var definitions = new HashMap(); if (tracing.isEnabled()) { definitions.put("LF_TRACE", tracing.traceFileName); diff --git a/core/src/main/java/org/lflang/generator/c/CTracingGenerator.java b/core/src/main/java/org/lflang/generator/c/CTracingGenerator.java index b013913756..8439d562b0 100644 --- a/core/src/main/java/org/lflang/generator/c/CTracingGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTracingGenerator.java @@ -30,12 +30,10 @@ public static String generateTraceTableEntries(ReactorInstance instance) { List code = new ArrayList<>(); var description = CUtil.getShortenedName(instance); var selfStruct = CUtil.reactorRef(instance); - var envTraceRef = CUtil.getEnvironmentStruct(instance) + ".trace"; - code.add(registerTraceEvent(envTraceRef, selfStruct, "NULL", "trace_reactor", description)); + code.add(registerTraceEvent(selfStruct, "NULL", "trace_reactor", description)); for (ActionInstance action : instance.actions) { code.add( registerTraceEvent( - envTraceRef, selfStruct, getTrigger(selfStruct, action.getName()), "trace_trigger", @@ -44,7 +42,6 @@ public static String generateTraceTableEntries(ReactorInstance instance) { for (TimerInstance timer : instance.timers) { code.add( registerTraceEvent( - envTraceRef, selfStruct, getTrigger(selfStruct, timer.getName()), "trace_trigger", @@ -54,10 +51,8 @@ public static String generateTraceTableEntries(ReactorInstance instance) { } private static String registerTraceEvent( - String envTrace, String obj, String trigger, String type, String description) { + String obj, String trigger, String type, String description) { return "_lf_register_trace_event(" - + envTrace - + ", " + obj + ", " + trigger diff --git a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java index bd4f844912..ae2d91bc40 100644 --- a/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java +++ b/core/src/main/java/org/lflang/generator/c/CTriggerObjectsGenerator.java @@ -230,10 +230,12 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde if (levelSet.size() == 1 && deadlineSet.size() == 1) { // Scenario (1) - - var indexValue = inferredDeadline.toNanoSeconds() << 16 | level; - - var reactionIndex = "0x" + Long.toUnsignedString(indexValue, 16) + "LL"; + var reactionIndex = + "lf_combine_deadline_and_level(" + + inferredDeadline.toNanoSeconds() + + ", " + + level + + ")"; temp.pr( String.join( @@ -251,13 +253,13 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) - + ".index = (" + + ".index = lf_combine_deadline_and_level(" + r.uniqueID() + "_inferred_deadlines[" + runtimeIdx - + "] << 16) | " + + "], " + level - + ";")); + + ");")); } else if (levelSet.size() > 1 && deadlineSet.size() == 1) { // Scenarion (3) @@ -268,13 +270,13 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) - + ".index = (" + + ".index = lf_combine_deadline_and_level(" + inferredDeadline.toNanoSeconds() - + " << 16) | " + + ", " + r.uniqueID() + "_levels[" + runtimeIdx - + "];")); + + "]);")); } else if (levelSet.size() > 1 && deadlineSet.size() > 1) { // Scenario (4) @@ -285,15 +287,15 @@ private static boolean setReactionPriorities(ReactorInstance reactor, CodeBuilde "// index is the OR of levels[" + runtimeIdx + "] and ", "// deadlines[" + runtimeIdx + "] shifted left 16 bits.", CUtil.reactionRef(r) - + ".index = (" + + ".index = inferredDeadline.toNanoSeconds(" + r.uniqueID() + "_inferred_deadlines[" + runtimeIdx - + "] << 16) | " + + "], " + r.uniqueID() + "_levels[" + runtimeIdx - + "];")); + + "]);")); } } for (ReactorInstance child : reactor.children) { @@ -569,7 +571,7 @@ private static String deferredFillTriggerTable(Iterable reacti "// For reaction " + reaction.index + " of " + name + ", allocate an", "// array of trigger pointers for downstream reactions through port " + port.getFullName(), - "trigger_t** trigger_array = (trigger_t**)_lf_allocate(", + "trigger_t** trigger_array = (trigger_t**)lf_allocate(", " " + srcRange.destinations.size() + ", sizeof(trigger_t*),", " &" + reactorSelfStruct + "->base.allocations); ", triggerArray + " = trigger_array;")); @@ -967,13 +969,13 @@ private static String deferredReactionOutputs( "\n", "// Allocate memory for triggers[] and triggered_sizes[] on the reaction_t", "// struct for this reaction.", - CUtil.reactionRef(reaction) + ".triggers = (trigger_t***)_lf_allocate(", + CUtil.reactionRef(reaction) + ".triggers = (trigger_t***)lf_allocate(", " " + outputCount + ", sizeof(trigger_t**),", " &" + reactorSelfStruct + "->base.allocations);", - CUtil.reactionRef(reaction) + ".triggered_sizes = (int*)_lf_allocate(", + CUtil.reactionRef(reaction) + ".triggered_sizes = (int*)lf_allocate(", " " + outputCount + ", sizeof(int),", " &" + reactorSelfStruct + "->base.allocations);", - CUtil.reactionRef(reaction) + ".output_produced = (bool**)_lf_allocate(", + CUtil.reactionRef(reaction) + ".output_produced = (bool**)lf_allocate(", " " + outputCount + ", sizeof(bool*),", " &" + reactorSelfStruct + "->base.allocations);")); } @@ -1029,7 +1031,7 @@ private static String deferredReactionMemory( + width + ";", CUtil.reactorRefNested(trigger.getParent()) + "." + trigger.getName(), - " = (" + portStructType + "**)_lf_allocate(", + " = (" + portStructType + "**)lf_allocate(", " " + width + ", sizeof(" + portStructType + "*),", " &" + reactorSelfStruct + "->base.allocations); ")); @@ -1071,11 +1073,11 @@ private static String deferredAllocationForEffectsOnInputs(ReactorInstance react effectRef + "_width = " + effect.getWidth() + ";", "// Allocate memory to store output of reaction feeding ", "// a multiport input of a contained reactor.", - effectRef + " = (" + portStructType + "**)_lf_allocate(", + effectRef + " = (" + portStructType + "**)lf_allocate(", " " + effect.getWidth() + ", sizeof(" + portStructType + "*),", " &" + reactorSelfStruct + "->base.allocations); ", "for (int i = 0; i < " + effect.getWidth() + "; i++) {", - " " + effectRef + "[i] = (" + portStructType + "*)_lf_allocate(", + " " + effectRef + "[i] = (" + portStructType + "*)lf_allocate(", " 1, sizeof(" + portStructType + "),", " &" + reactorSelfStruct + "->base.allocations); ", "}")); diff --git a/core/src/main/java/org/lflang/generator/docker/CDockerGenerator.java b/core/src/main/java/org/lflang/generator/docker/CDockerGenerator.java index d3e4c64eeb..62c61ed216 100644 --- a/core/src/main/java/org/lflang/generator/docker/CDockerGenerator.java +++ b/core/src/main/java/org/lflang/generator/docker/CDockerGenerator.java @@ -40,7 +40,7 @@ protected String generateDockerFileContent() { "# For instructions, see: https://www.lf-lang.org/docs/handbook/containerized-execution", "FROM " + baseImage + " AS builder", "WORKDIR /lingua-franca/" + lfModuleName, - "RUN set -ex && apk add --no-cache " + compiler + " musl-dev cmake make", + generateRunForBuildDependencies(), "COPY . src-gen", compileCommand, "", diff --git a/core/src/main/java/org/lflang/target/Target.java b/core/src/main/java/org/lflang/target/Target.java index a01b863303..573b121566 100644 --- a/core/src/main/java/org/lflang/target/Target.java +++ b/core/src/main/java/org/lflang/target/Target.java @@ -57,6 +57,7 @@ import org.lflang.target.property.SchedulerProperty; import org.lflang.target.property.SingleFileProjectProperty; import org.lflang.target.property.SingleThreadedProperty; +import org.lflang.target.property.TracePluginProperty; import org.lflang.target.property.TracingProperty; import org.lflang.target.property.VerifyProperty; import org.lflang.target.property.WorkersProperty; @@ -605,6 +606,7 @@ public void initialize(TargetConfig config) { SchedulerProperty.INSTANCE, SingleThreadedProperty.INSTANCE, TracingProperty.INSTANCE, + TracePluginProperty.INSTANCE, VerifyProperty.INSTANCE, WorkersProperty.INSTANCE); case CPP -> config.register( diff --git a/core/src/main/java/org/lflang/target/TargetConfig.java b/core/src/main/java/org/lflang/target/TargetConfig.java index 6170947db0..f3dc1695f6 100644 --- a/core/src/main/java/org/lflang/target/TargetConfig.java +++ b/core/src/main/java/org/lflang/target/TargetConfig.java @@ -63,6 +63,10 @@ */ public class TargetConfig { + /** Error message to use when a target property does not exist in LF syntax. */ + public static final String NOT_IN_LF_SYNTAX_MESSAGE = + "There is no representation of this property in the LF target property syntax"; + /** The target of this configuration (e.g., C, TypeScript, Python). */ public final Target target; @@ -173,10 +177,9 @@ protected void load(JsonObject jsonObject, MessageReporter messageReporter) { * @param stage2 The second stage an the error reporter through which to report the warning. */ public void reportUnsupportedTargetProperty(String name, MessageReporter.Stage2 stage2) { - stage2.warning( + stage2.error( String.format( - "The target property '%s' is not supported by the %s target and is thus ignored.", - name, this.target)); + "The target property '%s' is not supported by the %s target.", name, this.target)); stage2.info("Recognized properties are: " + this.listOfRegisteredProperties()); } diff --git a/core/src/main/java/org/lflang/target/property/TargetProperty.java b/core/src/main/java/org/lflang/target/property/TargetProperty.java index d2d630d6b3..e1e1c444df 100644 --- a/core/src/main/java/org/lflang/target/property/TargetProperty.java +++ b/core/src/main/java/org/lflang/target/property/TargetProperty.java @@ -126,7 +126,9 @@ public void update(TargetConfig config, T value) { } /** - * Update the given configuration based on the given corresponding AST node. + * Update the given configuration based on the given corresponding AST node. If the given + * configuration does not belong in the AST, then report an error using the error message given by + * {@code TargetConfig.NOT_IN_LF_SYNTAX_MESSAGE}. * * @param config The configuration to update. * @param pair The pair that holds the value to perform the update with. diff --git a/core/src/main/java/org/lflang/target/property/TracePluginProperty.java b/core/src/main/java/org/lflang/target/property/TracePluginProperty.java new file mode 100644 index 0000000000..2d150b9fab --- /dev/null +++ b/core/src/main/java/org/lflang/target/property/TracePluginProperty.java @@ -0,0 +1,56 @@ +package org.lflang.target.property; + +import org.lflang.MessageReporter; +import org.lflang.lf.Element; +import org.lflang.target.TargetConfig; +import org.lflang.target.property.TracePluginProperty.TracePluginOptions; +import org.lflang.target.property.type.PrimitiveType; + +/** Property that provides an alternative tracing implementation. */ +public class TracePluginProperty extends TargetProperty { + + /** Singleton target property instance. */ + public static final TracePluginProperty INSTANCE = new TracePluginProperty(); + + private TracePluginProperty() { + super(PrimitiveType.STRING); + } + + @Override + public TracePluginOptions initialValue() { + return null; + } + + @Override + protected TracePluginOptions fromAst(Element node, MessageReporter reporter) { + reporter.at(node).error(TargetConfig.NOT_IN_LF_SYNTAX_MESSAGE); + return null; + } + + @Override + protected TracePluginOptions fromString(String s, MessageReporter reporter) { + return new TracePluginOptions(s); + } + + @Override + public String name() { + return "trace-plugin"; + } + + @Override + public Element toAstElement(TracePluginOptions value) { + throw new UnsupportedOperationException(TargetConfig.NOT_IN_LF_SYNTAX_MESSAGE); + } + + public static class TracePluginOptions { + private final String implementationArchiveFile; + + public TracePluginOptions(String implementationArchiveFile) { + this.implementationArchiveFile = implementationArchiveFile; + } + + public String getImplementationArchiveFile() { + return implementationArchiveFile; + } + } +} diff --git a/core/src/main/java/org/lflang/util/FileUtil.java b/core/src/main/java/org/lflang/util/FileUtil.java index ade0def1c2..67b62d9a59 100644 --- a/core/src/main/java/org/lflang/util/FileUtil.java +++ b/core/src/main/java/org/lflang/util/FileUtil.java @@ -663,6 +663,7 @@ public static void arduinoDeleteHelper(Path srcGenPath, boolean threadingOn) thr deleteDirectory(srcGenPath.resolve("include/core/threaded")); deleteDirectory(srcGenPath.resolve("src/core/platform/arduino_mbed")); } + deleteDirectory(srcGenPath.resolve("src").resolve("trace")); // Delete all the federated headers deleteDirectory(srcGenPath.resolve("include/core/federated")); // arduino-cli needs all headers to be under a "include" directory. @@ -748,7 +749,9 @@ public static void relativeIncludeHelper( if (path.getFileName().toString().contains("CMakeLists.txt")) continue; if (fileStringToFilePath.put(fileName, path) != null) { throw new IOException( - "Directory has different files with the same name. Cannot Relativize."); + String.format( + "Directory has different files with the same name (%s). Cannot relativize.", + fileName)); } } Pattern regexExpression = Pattern.compile("#include\s+[\"]([^\"]+)*[\"]"); diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt index 1a12f6424a..b09ebffb6b 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppAssembleMethodGenerator.kt @@ -30,6 +30,7 @@ import org.lflang.generator.cpp.CppInstanceGenerator.Companion.isEnclave import org.lflang.generator.cpp.CppPortGenerator.Companion.dataType import org.lflang.lf.Action import org.lflang.lf.Connection +import org.lflang.lf.Instantiation import org.lflang.lf.ParameterReference import org.lflang.lf.Port import org.lflang.lf.Reaction @@ -51,22 +52,23 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { generateCode: (String) -> String ): String { val port = varRef.variable as Port - val container = varRef.container + val container: Instantiation? = varRef.container + val instanceRef = if (container?.isEnclave == true) "__lf_instance->" else "" return with(PrependOperator) { if (port.isMultiport) { if (container?.isBank == true) { if (varRef.isInterleaved) { """ - |for (size_t __lf_port_idx = 0; __lf_port_idx < ${container.name}[0]->${port.name}.size(); __lf_port_idx++) { + |for (size_t __lf_port_idx = 0; __lf_port_idx < ${container.name}[0]->$instanceRef${port.name}.size(); __lf_port_idx++) { | for (auto& __lf_instance : ${container.name}) { - ${" | "..generateCode("__lf_instance->${port.name}[__lf_port_idx]")} + ${" | "..generateCode("__lf_instance->$instanceRef${port.name}[__lf_port_idx]")} | } |} """.trimMargin() } else { """ |for (auto& __lf_instance : ${container.name}) { - | for (auto& __lf_port : __lf_instance->${port.name}) { + | for (auto& __lf_port : __lf_instance->$instanceRef${port.name}) { ${" | "..generateCode("__lf_port")} | } |} @@ -85,7 +87,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { // is in a bank, but not a multiport """ |for (auto& __lf_instance : ${container.name}) { - ${" | "..generateCode("__lf_instance->${if(container.isEnclave) "__lf_instance->" else ""}${port.name}")} + ${" | "..generateCode("__lf_instance->$instanceRef${port.name}")} |} """.trimMargin() } else { @@ -197,7 +199,7 @@ class CppAssembleMethodGenerator(private val reactor: Reactor) { private fun Connection.getConnectionLambda(portType: String): String { return """ - [this]($portType left, $portType right) { + [&]($portType left, $portType right) { left->environment()->draw_connection(left, right, $properties); } """.trimIndent() diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppParameterGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppParameterGenerator.kt index 3c2224e031..3cd064b1ad 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppParameterGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppParameterGenerator.kt @@ -67,5 +67,7 @@ class CppParameterGenerator(private val reactor: Reactor) { * This is required for some code bodies (e.g. target code in parameter initializers) to have access to the local parameters. */ fun generateOuterAliasDeclarations() = - reactor.parameters.joinToString(separator = "") { "const typename Parameters::${it.typeAlias}& ${it.name} = __lf_inner.${it.name};\n" } + reactor.parameters.joinToString(prefix = "// parameter aliases for use in the outer scope\n", separator = "") { + "[[maybe_unused]] const typename Parameters::${it.typeAlias}& ${it.name} = __lf_inner.${it.name};\n" + } } diff --git a/core/src/main/kotlin/org/lflang/generator/cpp/CppReactorGenerator.kt b/core/src/main/kotlin/org/lflang/generator/cpp/CppReactorGenerator.kt index e6cf197e06..97bf0541e4 100644 --- a/core/src/main/kotlin/org/lflang/generator/cpp/CppReactorGenerator.kt +++ b/core/src/main/kotlin/org/lflang/generator/cpp/CppReactorGenerator.kt @@ -94,8 +94,8 @@ class CppReactorGenerator(private val reactor: Reactor, fileConfig: CppFileConfi ${" | "..reactions.generateReactionViewForwardDeclarations()} | | class Inner: public lfutil::LFScope { - | const Inner& __lf_inner = *this; - | const Parameters __lf_parameters; + | [[maybe_unused]] const Inner& __lf_inner = *this; + | [[maybe_unused]] const Parameters __lf_parameters; ${" | "..parameters.generateInnerAliasDeclarations()} ${" | "..state.generateDeclarations()} ${" | "..methods.generateDeclarations()} diff --git a/core/src/main/resources/lib/c/reactor-c b/core/src/main/resources/lib/c/reactor-c index 18fd6ee621..277d3f2951 160000 --- a/core/src/main/resources/lib/c/reactor-c +++ b/core/src/main/resources/lib/c/reactor-c @@ -1 +1 @@ -Subproject commit 18fd6ee6212ba127aea5d7918e26a6e28d4068e7 +Subproject commit 277d3f295167b9f9f3b45356937af8cf57bef3b8 diff --git a/core/src/main/resources/lib/platform/zephyr/prj_lf.conf b/core/src/main/resources/lib/platform/zephyr/prj_lf.conf index 88613edc08..6b171daff2 100644 --- a/core/src/main/resources/lib/platform/zephyr/prj_lf.conf +++ b/core/src/main/resources/lib/platform/zephyr/prj_lf.conf @@ -12,3 +12,4 @@ CONFIG_NEWLIB_LIBC=y CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y # Enable the counter API used for hi-res clock CONFIG_COUNTER=y +CONFIG_THREAD_CUSTOM_DATA=y diff --git a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java index 11fff6c2c9..577c02eb23 100644 --- a/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java +++ b/core/src/test/java/org/lflang/tests/compiler/LinguaFrancaValidationTest.java @@ -34,6 +34,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import org.eclipse.xtext.diagnostics.Severity; import org.eclipse.xtext.testing.InjectWith; import org.eclipse.xtext.testing.extensions.InjectionExtension; import org.eclipse.xtext.testing.util.ParseHelper; @@ -1580,7 +1581,17 @@ public Collection checkTargetProperties() throws Exception { Model model = createModel(Target.C, property, it); System.out.println(property.name()); System.out.println(it.toString()); - validator.assertNoErrors(model); + var issues = validator.validate(model); + if (!issues.stream() + .allMatch( + issue -> + issue.getSeverity() != Severity.ERROR + || issue + .getMessage() + .equals(TargetConfig.NOT_IN_LF_SYNTAX_MESSAGE))) { + throw new RuntimeException( + "there were unexpected errors in the generated model"); + } // Also make sure warnings are produced when files are not present. if (type == PrimitiveType.FILE) { validator.assertWarning( @@ -1905,11 +1916,11 @@ public void testInvalidTargetParam() throws Exception { var model = parseWithoutError(testCase); List issues = validator.validate(model); Assertions.assertTrue(issues.size() == 2); - validator.assertWarning( + validator.assertError( model, LfPackage.eINSTANCE.getKeyValuePair(), null, - "The target property 'foobarbaz' is not supported by the C target and is thus ignored."); + "The target property 'foobarbaz' is not supported by the C target."); } @Test @@ -1922,12 +1933,11 @@ public void testTargetParamNotSupportedForTarget() throws Exception { var model = parseWithoutError(testCase); List issues = validator.validate(model); Assertions.assertTrue(issues.size() == 2); - validator.assertWarning( + validator.assertError( model, LfPackage.eINSTANCE.getKeyValuePair(), null, - "The target property 'cargo-features' is not supported by the Python target and is thus" - + " ignored."); + "The target property 'cargo-features' is not supported by the Python target."); } @Test diff --git a/test/C/src/concurrent/Threaded.lf b/test/C/src/concurrent/Threaded.lf index 88a9acd6b6..a9598ca610 100644 --- a/test/C/src/concurrent/Threaded.lf +++ b/test/C/src/concurrent/Threaded.lf @@ -6,8 +6,7 @@ // that without threads, this takes more than 800 msec to complete 200 msec of logical time. See // ThreadedMultiport for a parameterized version of this. target C { - timeout: 2 sec, - flags: "" // Disable compiler optimization so that TakeTime actually takes time. + timeout: 2 sec } reactor Source { diff --git a/test/C/src/concurrent/ThreadedMultiport.lf b/test/C/src/concurrent/ThreadedMultiport.lf index 6fce42f0e9..cc09d36868 100644 --- a/test/C/src/concurrent/ThreadedMultiport.lf +++ b/test/C/src/concurrent/ThreadedMultiport.lf @@ -1,7 +1,6 @@ // Check multiport capabilities on Outputs. target C { - timeout: 2 sec, - flags: "" // Disable compiler optimization so that TakeTime actually takes time. + timeout: 2 sec } reactor Source(width: int = 4) { diff --git a/test/C/src/concurrent/ThreadedThreaded.lf b/test/C/src/concurrent/ThreadedThreaded.lf index 0b011b3118..6ad5204e02 100644 --- a/test/C/src/concurrent/ThreadedThreaded.lf +++ b/test/C/src/concurrent/ThreadedThreaded.lf @@ -6,8 +6,7 @@ // of this. target C { timeout: 2 sec, - tracing: true, - flags: "" // Disable compiler optimization so that TakeTime actually takes time. + tracing: true } reactor Source { diff --git a/test/C/src/concurrent/Tracing.lf b/test/C/src/concurrent/Tracing.lf index 983c9e737a..e0b0deb41b 100644 --- a/test/C/src/concurrent/Tracing.lf +++ b/test/C/src/concurrent/Tracing.lf @@ -2,7 +2,6 @@ target C { timeout: 2 sec, tracing: true, - flags: "", // Disable compiler optimization so that TakeTime actually takes time. logging: DEBUG } diff --git a/test/C/src/federated/LoopDistributedCentralizedPhysicalAction.lf b/test/C/src/federated/LoopDistributedCentralizedPhysicalAction.lf index ac783f07cc..59931b7f2c 100644 --- a/test/C/src/federated/LoopDistributedCentralizedPhysicalAction.lf +++ b/test/C/src/federated/LoopDistributedCentralizedPhysicalAction.lf @@ -4,7 +4,6 @@ * @author Edward A. Lee */ target C { - flags: "-Wall", coordination: centralized, coordination-options: { advance-message-interval: 100 msec diff --git a/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf b/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf index 51a10faac2..6b495a29d9 100644 --- a/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf +++ b/test/C/src/federated/LoopDistributedCentralizedPrecedence.lf @@ -6,7 +6,6 @@ * @author Soroush Bateni */ target C { - flags: "-Wall", coordination: centralized, coordination-options: { advance-message-interval: 100 msec diff --git a/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf b/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf index 82adfca699..9d33a7ec1f 100644 --- a/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf +++ b/test/C/src/federated/LoopDistributedCentralizedPrecedenceHierarchy.lf @@ -6,7 +6,6 @@ * @author Soroush Bateni */ target C { - flags: "-Wall", coordination: centralized, coordination-options: { advance-message-interval: 100 msec diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBank.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBank.lf new file mode 100644 index 0000000000..92c03efdee --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBank.lf @@ -0,0 +1,67 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Src(bank_index: std::size_t = 0) { + timer t(0, 100 ms) + output[4] out: int + state counter: int = 0 + + reaction(t) -> out {= + for (auto& port : out) { + port.set(bank_index + counter); + } + counter = counter + 4; + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50 ms) + input[4] in: int + state received: bool = false + state iteration: int = 0 + + reaction(in) {= + received = true; + int value[4] = {0,0,0,0}; + for(int i=0; i<4; i++){ + value[i] = *in[i].get(); + reactor::log::Info() << "Sink"<< bank_index << ": Received " << value[i] << " in port:" << i << " at " << get_elapsed_logical_time(); + } + + for(int i=0; i<4; i++){ + if (value[i] != iteration*4 + bank_index) { + reactor::log::Error() << "Expected to recive " << iteration*4 + bank_index; + exit(1); + } + } + + auto expected = 100ms * iteration; + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave(each = true) + src = new[4] Src() + @enclave(each = true) + sink = new[4] Sink() + + src.out -> sink.in +} diff --git a/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBankInterleave.lf b/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBankInterleave.lf new file mode 100644 index 0000000000..aabce4bbd9 --- /dev/null +++ b/test/Cpp/src/enclave/EnclaveCommunicationMultiportBankToMultiportBankInterleave.lf @@ -0,0 +1,67 @@ +target Cpp { + timeout: 1 s, + workers: 1 +} + +reactor Src(bank_index: std::size_t = 0) { + timer t(0, 100 ms) + output[4] out: int + state counter: int = 0 + + reaction(t) -> out {= + for (auto& port : out) { + port.set(bank_index + counter); + } + counter = counter + 4; + =} +} + +reactor Sink(bank_index: std::size_t = 0) { + timer t(0, 50 ms) + input[4] in: int + state received: bool = false + state iteration: int = 0 + + reaction(in) {= + received = true; + int value[4] = {0,0,0,0}; + for(int i=0; i<4; i++){ + value[i] = *in[i].get(); + reactor::log::Info() << "Sink"<< bank_index << ": Received " << value[i] << " in port:" << i << " at " << get_elapsed_logical_time(); + } + + for(int i=0; i<4; i++){ + if (value[i] != iteration*4 + i) { + reactor::log::Error() << "Expected to recive " << iteration*4 + i; + exit(1); + } + } + + auto expected = 100ms * iteration; + iteration++; + if (get_elapsed_logical_time() != expected) { + reactor::log::Error() << "Expected value at " << expected; + exit(1); + } + =} + + reaction(shutdown) {= + if(!received) { + reactor::log::Error() << "Nothing received."; + exit(1); + } + =} + + reaction(t) {= + reactor::log::Info() << "Tick"; + =} +} + +main reactor { + @enclave(each = true) + src = new[4] Src() + @enclave(each = true) + sink = new[4] Sink() + + src.out -> interleaved(sink.in) +} diff --git a/test/Cpp/src/multiport/MultiportToMultiportAfterParameterized.lf b/test/Cpp/src/multiport/MultiportToMultiportAfterParameterized.lf new file mode 100644 index 0000000000..d0b1b6ae6e --- /dev/null +++ b/test/Cpp/src/multiport/MultiportToMultiportAfterParameterized.lf @@ -0,0 +1,42 @@ +// Test multiport to multiport connections. See also MultiportToMultiport. +target Cpp + +reactor Source(width: size_t = 2) { + output[width] out: size_t + + reaction(startup) -> out {= + for (size_t i = 0; i < out.size(); i++) { + out[i].set(i); + } + =} +} + +reactor Destination(width: size_t = 2) { + input[width] in: size_t + + reaction(in) {= + for (size_t i = 0; i < in.size(); i++) { + if (in[i].is_present()) { + size_t value = *in[i].get(); + std::cout << "Received on channel " << i << ": " << value << '\n'; + // NOTE: For testing purposes, this assumes the specific + // widths instantiated below. + if (value != i % 3) { + std::cerr << "ERROR: expected " << i % 3 << '\n'; + exit(1); + } + } + } + if (get_elapsed_logical_time() != 1s) { + std::cerr << "ERROR: Expected to receive input after one second.\n"; + exit(2); + } + =} +} + +main reactor(delay: time = 1 sec) { + a1 = new Source(width=3) + a2 = new Source(width=2) + b = new Destination(width=5) + a1.out, a2.out -> b.in after delay +}