From 98b0104c7bf526c6fe0c8ddb8b0a059be82f5bc7 Mon Sep 17 00:00:00 2001 From: giles Date: Sun, 28 Jun 2026 17:48:47 +0000 Subject: [PATCH] erlang: send_after deadline-ordering + cancel-of-fired tests (T3+T4, 769/769) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit T3 — concurrent timers fire in deadline order, not schedule order (scheduler jumps the clock to the earliest pending deadline each time the runnable queue drains). T4 — cancel_timer on an already-fired timer returns the atom false. Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/erlang/scoreboard.json | 6 ++--- lib/erlang/scoreboard.md | 4 ++-- lib/erlang/tests/send_after.sx | 40 ++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/lib/erlang/scoreboard.json b/lib/erlang/scoreboard.json index 3f06c462..ede12189 100644 --- a/lib/erlang/scoreboard.json +++ b/lib/erlang/scoreboard.json @@ -1,7 +1,7 @@ { "language": "erlang", - "total_pass": 766, - "total": 766, + "total_pass": 769, + "total": 769, "suites": [ {"name":"tokenize","pass":62,"total":62,"status":"ok"}, {"name":"parse","pass":52,"total":52,"status":"ok"}, @@ -14,6 +14,6 @@ {"name":"fib","pass":8,"total":8,"status":"ok"}, {"name":"ffi","pass":37,"total":37,"status":"ok"}, {"name":"vm","pass":78,"total":78,"status":"ok"}, - {"name":"send_after","pass":5,"total":5,"status":"ok"} + {"name":"send_after","pass":8,"total":8,"status":"ok"} ] } diff --git a/lib/erlang/scoreboard.md b/lib/erlang/scoreboard.md index e83b5e9a..7afac274 100644 --- a/lib/erlang/scoreboard.md +++ b/lib/erlang/scoreboard.md @@ -1,6 +1,6 @@ # Erlang-on-SX Scoreboard -**Total: 766 / 766 tests passing** +**Total: 769 / 769 tests passing** | | Suite | Pass | Total | |---|---|---|---| @@ -15,7 +15,7 @@ | ✅ | fib | 8 | 8 | | ✅ | ffi | 37 | 37 | | ✅ | vm | 78 | 78 | -| ✅ | send_after | 5 | 5 | +| ✅ | send_after | 8 | 8 | Generated by `lib/erlang/conformance.sh`. diff --git a/lib/erlang/tests/send_after.sx b/lib/erlang/tests/send_after.sx index 1a83eff8..7b150f18 100644 --- a/lib/erlang/tests/send_after.sx +++ b/lib/erlang/tests/send_after.sx @@ -78,3 +78,43 @@ receive late -> got after 50 -> none end") :name) "none") + +;; ── T3 — multiple timers fire in deadline order, not schedule order ── +;; `b` is scheduled first (deadline 80) but `a` second (deadline 20). +;; Two plain receives drain the mailbox in arrival order — and arrival +;; is governed by deadline, so the first message out is `a`. +(er-sa-test + "T3 timers fire in deadline order" + (er-format-value + (sa-ev + "erlang:send_after(80, self(), b), + erlang:send_after(20, self(), a), + X = receive M1 -> M1 end, + Y = receive M2 -> M2 end, + {X, Y}")) + "{a,b}") + +;; A selective receive on `a` matches the earlier-deadline timer even +;; though `b` was scheduled first. +(er-sa-test + "T3 selective receive picks earliest deadline" + (get + (sa-ev + "erlang:send_after(80, self(), b), + erlang:send_after(20, self(), a), + receive a -> first end") + :name) + "first") + +;; ── T4 — cancel_timer on an already-fired timer returns false ────── +;; Once `x` has been received the timer has fired; cancelling its ref +;; now yields the atom `false`. +(er-sa-test + "T4 cancel of fired timer is false" + (get + (sa-ev + "Ref = erlang:send_after(20, self(), x), + receive x -> ok end, + erlang:cancel_timer(Ref)") + :name) + "false")