You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
I tried to save a few characters by inlining a send inside a join within an unroll_for! (the idea being to send in parallel and order subsequent channel ops after all the sends completing). The test behaved as if the send never happened (deadlock).
But if I instead use an explicit let binding for the send token, the procs no longer deadlock.
To Reproduce
Minimal repro:
proc DutProc {
control: chan<bool> in;
data: chan<u32>[2] in;
ack: chan<bool> out;
config(control: chan<bool> in, data: chan<u32>[2] in, ack: chan<bool> out) {
(control, data, ack)
}
init { }
next(state: ()) {
let (tok, ctrl, _) = recv_non_blocking(join(), control, false);
let (tok, _) = recv_if(tok, data[0], ctrl, u32:0);
let (tok, _) = recv_if(tok, data[1], ctrl, u32:0);
let tok = send_if(tok, ack, ctrl, true);
}
}
#[test_proc]
proc my_dut_test {
control: chan<bool> out;
data: chan<u32>[2] out;
ack: chan<bool> in;
terminator: chan<bool> out;
config(terminator: chan<bool> out) {
let (control_s, control_r) = chan<bool>("control");
let (data_s, data_r) = chan<u32>[2]("data");
let (ack_s, ack_r) = chan<bool>("complete");
spawn DutProc(control_r, data_r, ack_s);
(control_s, data_s, ack_r, terminator)
}
init { () }
next(state: ()) {
let tok = send(join(), control, true);
let sent_data_tok = unroll_for! (i, data_tok): (u32, token) in u32:0..u32:2 {
join(data_tok, send(tok, data[i], u32:1 + i))
}(join());
let (tok, done) = recv(sent_data_tok, ack);
assert_eq(done, true);
let tok = send(tok, terminator, true);
}
}
Running this DSLX test, you get the following error:
: internal error: DEADLINE_EXCEEDED: Procs are deadlocked:
dut.x:28:31-28:58: proc `DutProc` is blocked on receive on channel `my_dut_test->DutProc#0::data[0]`
dut.x:57:31-57:51: proc `my_dut_test` is blocked on receive on channel `my_dut_test::ack`
If you change the test_proc next so that the send gets its own let binding:
next(state: ()) {
let tok = send(join(), control, true);
let sent_data_tok = unroll_for! (i, data_tok): (u32, token) in u32:0..u32:2 {
let tok = send(tok, data[i], u32:1 + i);
join(data_tok, tok)
}(join());
let (tok, done) = recv(sent_data_tok, ack);
assert_eq(done, true);
let tok = send(tok, terminator, true);
}
the test will no longer deadlock.
Expected behavior
It shouldn't matter whether the send gets its own let binding.
The text was updated successfully, but these errors were encountered:
mikex-oss
added
bug
Something isn't working or is incorrect
dslx
DSLX (domain specific language) implementation / front-end
labels
Feb 24, 2025
Note: since there was some discussion about whether the deadlock is accidentally "fixed" because of the shadowing of the tok variable, the deadlock also goes away using a different binding inside the unroll_for!:
next(state: ()) {
let tok = send(join(), control, true);
let sent_data_tok = unroll_for! (i, data_tok): (u32, token) in u32:0..u32:2 {
let t = send(tok, data[i], u32:1 + i); // it doesn't matter if this is t or tok
join(data_tok, t)
}(join());
let (tok, done) = recv(sent_data_tok, ack);
assert_eq(done, true);
let tok = send(tok, terminator, true);
}
Describe the bug
I tried to save a few characters by inlining a
send
inside ajoin
within anunroll_for!
(the idea being to send in parallel and order subsequent channel ops after all the sends completing). The test behaved as if the send never happened (deadlock).But if I instead use an explicit
let
binding for thesend
token, the procs no longer deadlock.To Reproduce
Minimal repro:
Running this DSLX test, you get the following error:
If you change the test_proc
next
so that thesend
gets its ownlet
binding:the test will no longer deadlock.
Expected behavior
It shouldn't matter whether the
send
gets its ownlet
binding.The text was updated successfully, but these errors were encountered: