Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
133 lines
3.3 KiB
Plaintext
133 lines
3.3 KiB
Plaintext
;; Ring program — N processes in a ring, token passes M times.
|
|
;;
|
|
;; Each process waits for {setup, Next} so main can tie the knot
|
|
;; (can't reference a pid before spawning it). Once wired, main
|
|
;; injects the first token; each process forwards decrementing K
|
|
;; until it hits 0, at which point it signals `done` to main.
|
|
|
|
(define er-ring-test-count 0)
|
|
(define er-ring-test-pass 0)
|
|
(define er-ring-test-fails (list))
|
|
|
|
(define
|
|
er-ring-test
|
|
(fn
|
|
(name actual expected)
|
|
(set! er-ring-test-count (+ er-ring-test-count 1))
|
|
(if
|
|
(= actual expected)
|
|
(set! er-ring-test-pass (+ er-ring-test-pass 1))
|
|
(append! er-ring-test-fails {:actual actual :expected expected :name name}))))
|
|
|
|
(define ring-ev erlang-eval-ast)
|
|
|
|
(define
|
|
er-ring-program-3-6
|
|
"Me = self(),
|
|
Spawner = fun () ->
|
|
receive {setup, Next} ->
|
|
Loop = fun () ->
|
|
receive
|
|
{token, 0, Parent} -> Parent ! done;
|
|
{token, K, Parent} -> Next ! {token, K-1, Parent}, Loop()
|
|
end
|
|
end,
|
|
Loop()
|
|
end
|
|
end,
|
|
P1 = spawn(Spawner),
|
|
P2 = spawn(Spawner),
|
|
P3 = spawn(Spawner),
|
|
P1 ! {setup, P2},
|
|
P2 ! {setup, P3},
|
|
P3 ! {setup, P1},
|
|
P1 ! {token, 5, Me},
|
|
receive done -> finished end")
|
|
|
|
(er-ring-test
|
|
"ring N=3 M=6"
|
|
(get (ring-ev er-ring-program-3-6) :name)
|
|
"finished")
|
|
|
|
;; Two-node ring — token bounces twice between P1 and P2.
|
|
(er-ring-test
|
|
"ring N=2 M=4"
|
|
(get (ring-ev
|
|
"Me = self(),
|
|
Spawner = fun () ->
|
|
receive {setup, Next} ->
|
|
Loop = fun () ->
|
|
receive
|
|
{token, 0, Parent} -> Parent ! done;
|
|
{token, K, Parent} -> Next ! {token, K-1, Parent}, Loop()
|
|
end
|
|
end,
|
|
Loop()
|
|
end
|
|
end,
|
|
P1 = spawn(Spawner),
|
|
P2 = spawn(Spawner),
|
|
P1 ! {setup, P2},
|
|
P2 ! {setup, P1},
|
|
P1 ! {token, 3, Me},
|
|
receive done -> done end") :name)
|
|
"done")
|
|
|
|
;; Single-node "ring" — P sends to itself M times.
|
|
(er-ring-test
|
|
"ring N=1 M=5"
|
|
(get (ring-ev
|
|
"Me = self(),
|
|
Spawner = fun () ->
|
|
receive {setup, Next} ->
|
|
Loop = fun () ->
|
|
receive
|
|
{token, 0, Parent} -> Parent ! finished_loop;
|
|
{token, K, Parent} -> Next ! {token, K-1, Parent}, Loop()
|
|
end
|
|
end,
|
|
Loop()
|
|
end
|
|
end,
|
|
P = spawn(Spawner),
|
|
P ! {setup, P},
|
|
P ! {token, 4, Me},
|
|
receive finished_loop -> ok end") :name)
|
|
"ok")
|
|
|
|
;; Confirm the token really went around — count hops via io-buffer.
|
|
(er-ring-test
|
|
"ring N=3 M=9 hop count"
|
|
(do
|
|
(er-io-flush!)
|
|
(ring-ev
|
|
"Me = self(),
|
|
Spawner = fun () ->
|
|
receive {setup, Next} ->
|
|
Loop = fun () ->
|
|
receive
|
|
{token, 0, Parent} -> Parent ! done;
|
|
{token, K, Parent} ->
|
|
io:format(\"~p \", [K]),
|
|
Next ! {token, K-1, Parent},
|
|
Loop()
|
|
end
|
|
end,
|
|
Loop()
|
|
end
|
|
end,
|
|
P1 = spawn(Spawner),
|
|
P2 = spawn(Spawner),
|
|
P3 = spawn(Spawner),
|
|
P1 ! {setup, P2},
|
|
P2 ! {setup, P3},
|
|
P3 ! {setup, P1},
|
|
P1 ! {token, 8, Me},
|
|
receive done -> done end")
|
|
(er-io-buffer-content))
|
|
"8 7 6 5 4 3 2 1 ")
|
|
|
|
(define
|
|
er-ring-test-summary
|
|
(str "ring " er-ring-test-pass "/" er-ring-test-count))
|