Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add watchdogs to environment struct #2172

Merged
merged 23 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/main/java/org/lflang/generator/EnclaveInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class EnclaveInfo {
public int numWorkers = 1;
public int numModalReactors = 0;
public int numModalResetStates = 0;
public int numWatchdogs = 0;

public String traceFileName = null;
private ReactorInstance instance;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ private String generateCreateEnvironments() {
+ ","
+ enclave.enclaveInfo.numModalResetStates
+ ","
+ enclave.enclaveInfo.numWatchdogs
+ ","
+ traceFileName
+ ");");
}
Expand Down
6 changes: 1 addition & 5 deletions core/src/main/java/org/lflang/generator/c/CGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -615,9 +615,6 @@ private void generateCodeFor(String lfModuleName) throws IOException {
if (targetLanguageIsCpp()) code.pr("}");
}

// If there are watchdogs, create a table of triggers.
code.pr(CWatchdogGenerator.generateWatchdogTable(watchdogCount));

// Generate function to initialize the trigger objects for all reactors.
code.pr(
CTriggerObjectsGenerator.generateInitializeTriggerObjects(
Expand Down Expand Up @@ -1696,8 +1693,7 @@ public void generateReactorInstance(ReactorInstance instance) {
initializeOutputMultiports(instance);
initializeInputMultiports(instance);
recordBuiltinTriggers(instance);
watchdogCount +=
CWatchdogGenerator.generateInitializeWatchdogs(initializeTriggerObjects, instance);
CWatchdogGenerator.generateInitializeWatchdogs(initializeTriggerObjects, instance);

// Next, initialize the "self" struct with state variables.
// These values may be expressions that refer to the parameter values defined above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public static String generateInitializeTriggerObjects(
"int modal_state_reset_count[_num_enclaves] = {0};"
+ " SUPPRESS_UNUSED_WARNING(modal_state_reset_count);",
"int modal_reactor_count[_num_enclaves] = {0};"
+ " SUPPRESS_UNUSED_WARNING(modal_reactor_count);"));
+ " SUPPRESS_UNUSED_WARNING(modal_reactor_count);",
"int watchdog_count[_num_enclaves] = {0};"
+ " SUPPRESS_UNUSED_WARNING(watchdog_count);"));

// Create the table to initialize intended tag fields to 0 between time
// steps.
Expand Down
37 changes: 14 additions & 23 deletions core/src/main/java/org/lflang/generator/c/CWatchdogGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,33 @@ public static boolean hasWatchdogs(Reactor reactor) {
/**
* For the specified reactor instance, generate initialization code for each watchdog in the
* reactor. This code initializes the watchdog-related fields on the self struct of the reactor
* instance.
* instance. It also increments the watchdog count in the environment the parent reactor instance
* is within.
*
* @param code The place to put the code
* @param instance The reactor instance
* @return The count of watchdogs found in the reactor
*/
protected static int generateInitializeWatchdogs(CodeBuilder code, ReactorInstance instance) {
protected static void generateInitializeWatchdogs(CodeBuilder code, ReactorInstance instance) {
var foundOne = false;
var temp = new CodeBuilder();
var reactorRef = CUtil.reactorRef(instance);
int watchdogCount = 0;
var enclaveInfo = CUtil.getClosestEnclave(instance).enclaveInfo;
var enclaveStruct = CUtil.getEnvironmentStruct(instance);
var enclaveId = CUtil.getEnvironmentId(instance);

for (Watchdog watchdog :
ASTUtils.allWatchdogs(ASTUtils.toDefinition(instance.getDefinition().getReactorClass()))) {
var watchdogField = reactorRef + "->_lf_watchdog_" + watchdog.getName();
temp.pr(
String.join(
"\n",
"_lf_watchdogs[watchdog_number++] = &" + watchdogField + ";",
enclaveStruct
+ ".watchdogs[watchdog_count["
+ enclaveId
+ "]++] = &"
+ watchdogField
+ ";",
watchdogField
+ ".min_expiration = "
+ CTypes.getInstance()
Expand All @@ -83,8 +92,7 @@ protected static int generateInitializeWatchdogs(CodeBuilder code, ReactorInstan
if (foundOne) {
code.pr(temp.toString());
}
code.pr("SUPPRESS_UNUSED_WARNING(_lf_watchdog_count);");
return watchdogCount;
enclaveInfo.numWatchdogs += watchdogCount;
erlingrj marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down Expand Up @@ -154,23 +162,6 @@ protected static void generateWatchdogStruct(
* @param count The number of watchdogs found.
* @return The code that defines the table or a comment if count is 0.
*/
protected static String generateWatchdogTable(int count) {
if (count == 0) {
return String.join(
"\n",
"// No watchdogs found.",
"typedef void watchdog_t;",
"watchdog_t* _lf_watchdogs = NULL;",
"int _lf_watchdog_count = 0;");
}
return String.join(
"\n",
List.of(
"// Array of pointers to watchdog structs.",
"watchdog_t* _lf_watchdogs[" + count + "];",
"int _lf_watchdog_count = " + count + ";"));
}

/////////////////////////////////////////////////////////////////
// Private methods

Expand Down
66 changes: 66 additions & 0 deletions test/C/src/concurrent/Watchdog.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Test watchdog. This test starts a watchdog timer of 1500ms every 1s. Half the time, it then
* sleeps after starting the watchdog so that the watchdog expires. There should be a total of two
* watchdog expirations.
* @author Benjamin Asch
* @author Edward A. Lee
*/
target C {
timeout: 11000 ms
}

reactor Watcher(timeout: time = 1500 ms) {
// Offset ameliorates startup time.
timer t(1 s, 1 s)
// Period has to be smaller than watchdog timeout. Produced if the watchdog triggers.
output d: int
state count: int = 0

watchdog poodle(timeout) {=
instant_t p = lf_time_physical_elapsed();
lf_print("******** Watchdog timed out at elapsed physical time: " PRINTF_TIME, p);
self->count++;
=}

reaction(t) -> poodle, d {=
lf_watchdog_start(poodle, 0);
lf_print("Watchdog started at physical time " PRINTF_TIME, lf_time_physical_elapsed());
lf_print("Will expire at " PRINTF_TIME, lf_time_logical_elapsed() + self->timeout);
lf_set(d, 42);
=}

reaction(poodle) -> d {=
lf_print("Reaction poodle was called.");
lf_set(d, 1);
=}

reaction(shutdown) -> poodle {=
lf_watchdog_stop(poodle);
// Watchdog may expire in tests even without the sleep, but it should at least expire twice.
if (self->count < 2) {
lf_print_error_and_exit("Watchdog expired %d times. Expected at least 2.", self->count);
}
=}
}

main reactor {
logical action a
state count: int = 0

w = new Watcher()

reaction(w.d) {=
lf_print("Watcher reactor produced an output. %d", self->count % 2);
self->count++;
if (self->count % 4 == 0) {
lf_print(">>>>>> Taking a long time to process that output!");
lf_sleep(MSEC(1600));
}
=}

reaction(shutdown) {=
if (self->count < 12) {
lf_print_error_and_exit("Watchdog produced output %d times. Expected at least 12.", self->count);
}
=}
}
66 changes: 0 additions & 66 deletions test/C/src/concurrent/failing/Watchdog.lf

This file was deleted.

Loading