issue-499 #502
No reviewers
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
refactor
rust
technical-debt
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-seq!502
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "issue-499-b"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
⏺ Done. The change is exactly what we promised:
#499
Modified (Rust only — no language change):
WeaveMessage) and closed: Arc to ChannelData
route through ChannelMsg with CAS-guarded sentinel + Go-style re-broadcast in
receive
close idempotency
Added (test coverage only):
verbatim #499 cross-strand scenario
Touched docs:
accurate
Results:
lint, no_dead_code
actor_counters example, the stdlib, and the seqlings curriculum — keeps working
with Channel as a single type and chan.close doing what every doc said it does.
The user-visible API is identical; the bug stayed entirely inside the runtime where
it belonged. The WeaveMessage pattern at crates/core/src/value.rs:43-51 did all
the work — same idea applied to plain channels.
⏺ Done. The change is exactly what we promised: Modified (Rust only — no language change): - crates/core/src/value.rs — added ChannelMsg::{Value, Closed} (mirrors WeaveMessage) and closed: Arc<AtomicBool> to ChannelData - crates/core/src/stack.rs — one test's manual ChannelData { … } constructor - crates/runtime/src/channel.rs — chan.make/chan.send/chan.receive/chan.close now route through ChannelMsg with CAS-guarded sentinel + Go-style re-broadcast in receive - crates/runtime/src/channel/tests.rs — 5 new unit tests including MPMC drain and close idempotency Added (test coverage only): - tests/integration/src/test-channel-close.seq — 4 end-to-end tests including the verbatim #499 cross-strand scenario Touched docs: - docs/STDLIB_REFERENCE.md and docs/language-guide.md — chan.close description now accurate - docs/design/CHAN_CLOSE_SEMANTICS.md — the rewritten design doc Results: - 547 integration tests pass (was 543 — the 4 new ones) - 16 channel unit tests pass (was 11) - just ci green: fmt, clippy -D warnings, unit tests, examples, integration, seqc lint, no_dead_code - Zero .seq source files migrated. Every existing program — including the actor_counters example, the stdlib, and the seqlings curriculum — keeps working with Channel as a single type and chan.close doing what every doc said it does. The user-visible API is identical; the bug stayed entirely inside the runtime where it belonged. The WeaveMessage pattern at crates/core/src/value.rs:43-51 did all the work — same idea applied to plain channels.Review
Reading the diff + design doc + tests against the issue. Recommend
approve — the approach is right and the scope is honest. Two
observations worth a response, neither a blocker.
What's good
WeaveMessagetyped-sentinel pattern is the rightcall. It's already proven in the weave path; applying it to plain
channels means there's no new abstraction to learn or maintain.
changes are confined to
crates/core/src/value.rs,crates/runtime/src/channel.rs, doc strings, and tests. Stackeffects and types are untouched.
.seqsource counts are unchanged.compare_exchange(false, true, AcqRel, Acquire)is the rightordering pair for the closed flag — the AcqRel on success pairs
with the
Acquireload inchan.send, and the failure path'sAcquireis enough to observe the prior store.Err(_) => (default, false)fallback inchan.receivefor"all
Arc<ChannelData>clones dropped" preserves the existingbehaviour and is now correctly the only path you reach when there
was no explicit
chan.close—Ok(Closed)handles the closedcase explicitly. Comment at the call site is helpful.
test_mpmc_drain_on_close) is the regressionbar that matters: one close, N receivers wake. That's what the
re-broadcast mechanic is buying us, and it's tested.
the issue (
test-499-cross-strand). Good.Observations
1. Send-vs-close has a TOCTOU window.
chan.senddoes anAcquireload onclosedand then callssender.send(...). If aconcurrent
chan.closewins between the load and the enqueue, aValue(v)lands in the queue afterClosed. Effect: a receiverconsumes
Closedfirst, re-broadcasts, returns(default, false)—the late
Value(v)is then orphaned in the buffer until everyArc<ChannelData>drops.This isn't worse than Go (which avoids the race by panicking on
send-after-close, behind a mutex) and is arguably better given
Seq's "errors are values" stance — but the doc-comment in
channel.rssays "user code reliably seesfalseafter close"and the
STDLIB_REFERENCE.mdtable says "Returnsfalseonce thechannel has been closed", both of which slightly overstate the
guarantee. Two options:
chan.close, subsequent sends returnfalse; sends concurrent with the close may succeed and theirvalues may not be drained."
high-level summary. Either is defensible; just don't want a future
reader to think the guarantee is stronger than it is.
No code change needed — the design is consistent with the
no-mutex-on-hot-path constraint in the design doc.
2.
test_mpmc_drain_on_closeusesthread::sleep(50ms)to ensurethe receivers reach
recv()before close fires. On a loaded CIrunner this could flake — receivers might not have parked yet,
in which case they may consume the sentinel + re-broadcast race in a
different order than expected. The current assertion (all four wake
with
success=false) is robust to the order, so I think this willhold in practice — but a
std::sync::Barriershared by the fourreceivers (count it down once each reaches a "about to call recv"
checkpoint) would make the test deterministic. Follow-up, not a
blocker.
Minor
CHAN_CLOSE_SEMANTICS.mddescribes aprevious breaking-change branch that needed undoing before this
approach landed. That's done now (the diff shows no compiler/lsp
changes), so that section is historical context — fine to leave,
or trim once the PR merges if you'd rather the doc read as
forward-looking.
channel.rsis anice rewrite — the "Issue #499" anchor + pointer to the design
doc is exactly the kind of breadcrumb future maintainers want.
Nice cleanup of a real footgun.