diff --git a/org.lflang.tests/src/org/lflang/tests/Configurators.java b/org.lflang.tests/src/org/lflang/tests/Configurators.java index 24ee6f38f3..85a8465c29 100644 --- a/org.lflang.tests/src/org/lflang/tests/Configurators.java +++ b/org.lflang.tests/src/org/lflang/tests/Configurators.java @@ -25,6 +25,7 @@ package org.lflang.tests; import org.lflang.TargetProperty; +import org.lflang.TargetProperty.LogLevel; import org.lflang.TargetProperty.Platform; import org.lflang.tests.TestRegistry.TestCategory; @@ -63,13 +64,28 @@ public static boolean disableThreading(LFTest test) { return true; } - public static boolean makeZephyrCompatible(LFTest test) { + public static boolean makeZephyrCompatibleUnthreaded(LFTest test) { test.getContext().getArgs().setProperty("tracing", "false"); test.getContext().getTargetConfig().threading = false; test.getContext().getTargetConfig().setByUser.add(TargetProperty.THREADING); test.getContext().getTargetConfig().platformOptions.platform = Platform.ZEPHYR; test.getContext().getTargetConfig().platformOptions.flash = false; - test.getContext().getTargetConfig().platformOptions.board = "qemu_cortex_a53"; + test.getContext().getTargetConfig().platformOptions.board = "qemu_riscv32"; + // FIXME: Zephyr qemu emulations fails with debug log-levels. + test.getContext().getTargetConfig().logLevel = LogLevel.WARN; + test.getContext().getArgs().setProperty("logging", "warning"); + return true; + } + + public static boolean makeZephyrCompatible(LFTest test) { + test.getContext().getArgs().setProperty("tracing", "false"); + test.getContext().getTargetConfig().platformOptions.platform = Platform.ZEPHYR; + test.getContext().getTargetConfig().platformOptions.flash = false; + test.getContext().getTargetConfig().platformOptions.board = "qemu_riscv32"; + // FIXME: Zephyr qemu emulations fails with debug log-levels. + test.getContext().getTargetConfig().logLevel = LogLevel.WARN; + test.getContext().getArgs().setProperty("logging", "warning"); + return true; } /** diff --git a/org.lflang.tests/src/org/lflang/tests/runtime/CZephyrTest.java b/org.lflang.tests/src/org/lflang/tests/runtime/CZephyrTest.java index c151c1bb76..b29c2755d1 100644 --- a/org.lflang.tests/src/org/lflang/tests/runtime/CZephyrTest.java +++ b/org.lflang.tests/src/org/lflang/tests/runtime/CZephyrTest.java @@ -62,6 +62,19 @@ public void buildGenericTests() { List.of(Target.C), Message.DESC_GENERIC, TestCategory.GENERIC::equals, + Configurators::makeZephyrCompatibleUnthreaded, + TestLevel.BUILD, + false); + } + + @Test + public void buildConcurrentTests() { + Assumptions.assumeTrue(isLinux(), "Zephyr tests only run on Linux"); + + super.runTestsFor( + List.of(Target.C), + Message.DESC_CONCURRENT, + TestCategory.CONCURRENT::equals, Configurators::makeZephyrCompatible, TestLevel.BUILD, false); diff --git a/org.lflang/src/org/lflang/TargetConfig.java b/org.lflang/src/org/lflang/TargetConfig.java index c4794b4b1a..af805491da 100644 --- a/org.lflang/src/org/lflang/TargetConfig.java +++ b/org.lflang/src/org/lflang/TargetConfig.java @@ -397,6 +397,12 @@ public static class PlatformOptions { * you use to flash the boards. */ public boolean flash = false; + + /** + * The int value is used to determine the number of needed threads for the user application in + * Zephyr. + */ + public int userThreads = 0; } /** Settings related to tracing options. */ diff --git a/org.lflang/src/org/lflang/TargetProperty.java b/org.lflang/src/org/lflang/TargetProperty.java index b3abf815a3..796041b5f8 100644 --- a/org.lflang/src/org/lflang/TargetProperty.java +++ b/org.lflang/src/org/lflang/TargetProperty.java @@ -445,6 +445,9 @@ public enum TargetProperty { case PORT: pair.setValue(ASTUtils.toElement(config.platformOptions.port)); break; + case USER_THREADS: + pair.setValue(ASTUtils.toElement(config.platformOptions.userThreads)); + break; } kvp.getPairs().add(pair); } @@ -489,6 +492,9 @@ public enum TargetProperty { case PORT: config.platformOptions.port = ASTUtils.elementToSingleString(entry.getValue()); break; + case USER_THREADS: + config.platformOptions.userThreads = ASTUtils.toInteger(entry.getValue()); + break; default: break; } @@ -1629,7 +1635,8 @@ public enum PlatformOption implements DictionaryElement { BAUDRATE("baud-rate", PrimitiveType.NON_NEGATIVE_INTEGER), BOARD("board", PrimitiveType.STRING), FLASH("flash", PrimitiveType.BOOLEAN), - PORT("port", PrimitiveType.STRING); + PORT("port", PrimitiveType.STRING), + USER_THREADS("user-threads", PrimitiveType.NON_NEGATIVE_INTEGER); public final PrimitiveType type; diff --git a/org.lflang/src/org/lflang/generator/c/CGenerator.java b/org.lflang/src/org/lflang/generator/c/CGenerator.java index a8aeb271b5..f3accf165a 100644 --- a/org.lflang/src/org/lflang/generator/c/CGenerator.java +++ b/org.lflang/src/org/lflang/generator/c/CGenerator.java @@ -56,6 +56,7 @@ import org.lflang.TargetConfig; import org.lflang.TargetProperty; import org.lflang.TargetProperty.Platform; +import org.lflang.TargetProperty.PlatformOption; import org.lflang.ast.ASTUtils; import org.lflang.ast.DelayedConnectionTransformation; import org.lflang.federated.extensions.CExtensionUtils; @@ -713,9 +714,9 @@ private void generateCodeFor(String lfModuleName) throws IOException { // from the federation and close any open sockets. code.pr( """ - #ifndef FEDERATED - void terminate_execution() {} - #endif"""); + #ifndef FEDERATED + void terminate_execution() {} + #endif"""); // Generate functions for modes code.pr(CModesGenerator.generateLfInitializeModes(hasModalReactors)); @@ -1142,13 +1143,13 @@ protected void generateAuxiliaryStructs( federatedExtension.pr( String.format( """ - #ifdef FEDERATED - #ifdef FEDERATED_DECENTRALIZED - %s intended_tag; - #endif - %s physical_time_of_arrival; - #endif - """, + #ifdef FEDERATED + #ifdef FEDERATED_DECENTRALIZED + %s intended_tag; + #endif + %s physical_time_of_arrival; + #endif + """, types.getTargetTagType(), types.getTargetTimeType())); for (Port p : allPorts(tpr.reactor())) { builder.pr( @@ -2009,6 +2010,19 @@ protected void setUpGeneralParameters() { + " code only."); targetConfig.noCompile = true; } + + if (targetConfig.platformOptions.platform == Platform.ZEPHYR + && targetConfig.threading + && targetConfig.platformOptions.userThreads >= 0) { + targetConfig.compileDefinitions.put( + PlatformOption.USER_THREADS.name(), + String.valueOf(targetConfig.platformOptions.userThreads)); + } else if (targetConfig.platformOptions.userThreads > 0) { + errorReporter.reportWarning( + "Specifying user threads is only for threaded Lingua Franca on the Zephyr platform. This" + + " option will be ignored."); + } + if (targetConfig.threading) { // FIXME: This logic is duplicated in CMake pickScheduler(); // FIXME: this and pickScheduler should be combined. diff --git a/test/C/lib/libapp.a b/test/C/lib/libapp.a new file mode 100644 index 0000000000..d710e87c0e Binary files /dev/null and b/test/C/lib/libapp.a differ diff --git a/test/C/src/zephyr/Timer.lf b/test/C/src/zephyr/Timer.lf index d3cb3f96de..a3dd0e68cc 100644 --- a/test/C/src/zephyr/Timer.lf +++ b/test/C/src/zephyr/Timer.lf @@ -3,7 +3,6 @@ target C { name: Zephyr, board: qemu_cortex_m3 }, - threading: false, timeout: 10 sec } diff --git a/test/C/src/zephyr/UserThreads.lf b/test/C/src/zephyr/UserThreads.lf new file mode 100644 index 0000000000..115d8114a7 --- /dev/null +++ b/test/C/src/zephyr/UserThreads.lf @@ -0,0 +1,39 @@ +// Test user threads platform option for Zephyr. The application should be able +// to create exactly three threads. +target C { + platform: { + name: Zephyr, + user-threads: 3 + }, + threading: true, + workers: 2 +} + +main reactor { + preamble {= + #include "platform.h" + void func(void* arg) { + lf_print("Hello from user thread"); + } + + lf_thread_t thread_ids[4]; + =} + + reaction(startup) {= + int res; + + for (int i = 0; i < 3; i++) { + res = lf_thread_create(&thread_ids[i], &func, NULL); + if (res != 0) { + lf_print_error_and_exit("Could not create thread"); + } + } + + res = lf_thread_create(&thread_ids[3], &func, NULL); + if (res == 0) { + lf_print_error_and_exit("Could create more threads than specified."); + } else { + printf("SUCCESS: Created exactly three user threads.\n"); + } + =} +} diff --git a/util/RunZephyrTests.sh b/util/RunZephyrTests.sh index 742a23ef18..ffb15198a9 100755 --- a/util/RunZephyrTests.sh +++ b/util/RunZephyrTests.sh @@ -9,7 +9,7 @@ num_failures=0 failed_tests="" # Skip -skip=("FileReader" "FilePkgReader") +skip=("FileReader" "FilePkgReader" "Tracing" "ThreadedThreaded") find_kconfig_folders() { if [ -f "$folder/CMakeLists.txt" ]; then @@ -116,8 +116,7 @@ else fi echo "Number of passes: $num_successes" echo "Number of fails: $num_failures" -echo "Skipped tests: $skip" - +echo "Skipped tests: ${skip[@]}" if [ "$overall_success" = false ]; then echo "Failed tests: $failed_tests"