Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
118 changes: 49 additions & 69 deletions blog/2026-10-11-async-await.md → blog/2026-11-11-async-await.md

Large diffs are not rendered by default.

37 changes: 10 additions & 27 deletions blog/src/AsyncUserInput.lf
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,27 @@ reactor UserInput {
preamble {=
#include <stdio.h>
#include <stdlib.h>

// Read a line from stdin into dynamically allocated memory, dropping the
// trailing newline. The caller must free the result. Returns 0 on EOF or error.
size_t read_string(char** result) {
char* buffer = NULL;
size_t capacity = 0;
ssize_t nread = getline(&buffer, &capacity, stdin);
if (nread < 0) {
free(buffer);
return 0;
}
if (nread > 0 && buffer[nread - 1] == '\n') {
buffer[nread - 1] = '\0';
}
*result = buffer;
return nread;
}
=}
timer t(0, 5 s)
output out: char*
state count: int
physical action awake

// This reaction must precede the reaction that calls lf_async on the physical action.
// It causes that reaction to resume at the logical time of the physical action.
reaction(awake) {=
lf_async_resume(awake);
=}

reaction(startup) -> out, awake {=
reaction(startup, awake) -> out, awake {=
lf_print("Control-D to exit.");
while (true) {
char* line = NULL;
int nread = lf_async(awake, read_string, &line);
if (nread == 0) {
size_t capacity = 0;
int nread = lf_async(awake, getline, &line, &capacity, stdin);
if (nread < 0) {
lf_print("User input: EOF");
free(line);
lf_request_stop();
break;
}
// The logical time is now the physical time at which the line was read.
if (nread > 0 && line[nread - 1] == '\n') {
line[nread - 1] = '\0';
}
lf_set(out, line);
}
=}
Expand Down
35 changes: 35 additions & 0 deletions blog/src/AsyncUserInputPy.lf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
target Python {
keepalive: true
}

reactor UserInput {
timer t(0, 5 s)
output out
state count = 0
physical action awake

reaction(startup, awake) -> out, awake {=
print("Control-D to exit.")
while True:
try:
line = self.lf_async(awake, input)
# The logical time is now the physical time at which the line was read.
out.set(line)
except EOFError:
request_stop()
break
=}

reaction(t) -> out {=
out.set(f"{self.count}: Waiting for input...")
self.count += 1
=}
}

main reactor {
user_input = new UserInput()

reaction(user_input.out) {=
print(f"At logical time {lf.time.logical_elapsed()}, Line: {user_input.out.value}")
=}
}
8 changes: 1 addition & 7 deletions blog/src/AwaitLET.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ reactor RequestWork {
timer t(0, 200 ms)
state count: int = 1

// This reaction must precede the reaction that awaits the result.
// It causes that reaction to resume at the logical time of the result.
reaction(result) {=
lf_await_resume(result);
=}

reaction(t) result -> request {=
reaction(t, result) -> request {=
lf_print("Request work at logical time " PRINTF_TIME, lf_time_logical_elapsed());
lf_set(request, self->count++);
lf_await(result);
Expand Down
8 changes: 1 addition & 7 deletions blog/src/py/AwaitLET.lf → blog/src/AwaitLETPy.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ reactor RequestWork {
timer t(0, 200 ms)
state count = 1

# This reaction must precede the reaction that awaits the result.
# It causes that reaction to resume at the logical time of the result.
reaction(result) {=
self.lf_await_resume(result)
=}

reaction(t) result -> request {=
reaction(t, result) -> request {=
print(f"Request work at logical time {lf.time.logical_elapsed()}")
request.set(self.count)
self.count += 1
Expand Down
48 changes: 0 additions & 48 deletions blog/src/py/AsyncUserInput.lf

This file was deleted.

8 changes: 1 addition & 7 deletions docs/assets/code/c/src/AsyncUserInput.lf
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,7 @@ reactor UserInput {
state count: int
physical action awake

// This reaction must precede the reaction that calls lf_async on the physical action.
// It causes that reaction to resume at the logical time of the physical action.
reaction(awake) {=
lf_async_resume(awake);
=}

reaction(startup) -> out, awake {=
reaction(startup, awake) -> out, awake {=
while (true) {
char* line = NULL;
int nread = lf_async(awake, read_string, &line);
Expand Down
8 changes: 1 addition & 7 deletions docs/assets/code/c/src/AwaitLET.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ reactor RequestWork {
timer t(0, 200 ms)
state count: int = 1

// This reaction must precede the reaction that awaits the result.
// It causes that reaction to resume at the logical time of the result.
reaction(result) {=
lf_await_resume(result);
=}

reaction(t) result -> request {=
reaction(t, result) -> request {=
lf_print("Request work at logical time " PRINTF_TIME, lf_time_logical_elapsed());
lf_set(request, self->count++);
lf_await(result);
Expand Down
8 changes: 1 addition & 7 deletions docs/assets/code/py/src/AsyncUserInput.lf
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ reactor UserInput {
state count = 0
physical action awake

# This reaction must precede the reaction that calls lf_async on the physical action.
# It causes that reaction to resume at the logical time of the physical action.
reaction(awake) {=
self.lf_async_resume(awake)
=}

reaction(startup) -> out, awake {=
reaction(startup, awake) -> out, awake {=
while True:
line = self.lf_async(awake, read_string)
if line is None:
Expand Down
8 changes: 1 addition & 7 deletions docs/assets/code/py/src/AwaitLET.lf
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ reactor RequestWork {
timer t(0, 200 ms)
state count = 1

# This reaction must precede the reaction that awaits the result.
# It causes that reaction to resume at the logical time of the result.
reaction(result) {=
self.lf_await_resume(result)
=}

reaction(t) result -> request {=
reaction(t, result) -> request {=
print(f"Request work at logical time {lf.time.logical_elapsed()}")
request.set(self.count)
self.count += 1
Expand Down
2 changes: 1 addition & 1 deletion docs/assets/images/diagrams/AsyncUserInput.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/assets/images/diagrams/AwaitLET.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading