erlang: ring.erl + call/cc suspension rewrite (+4 ring tests)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Has been cancelled
This commit is contained in:
@@ -293,21 +293,23 @@
|
||||
(fn
|
||||
(vs)
|
||||
(cond
|
||||
(= (len vs) 1)
|
||||
(let
|
||||
((reason (nth vs 0)))
|
||||
(shift k (er-mk-exit-marker reason)))
|
||||
(= (len vs) 1) (raise (er-mk-exit-marker (nth vs 0)))
|
||||
(= (len vs) 2)
|
||||
(error
|
||||
"Erlang: exit/2 (signal another process) deferred to Phase 4 (links)")
|
||||
:else (error "Erlang: exit: wrong arity"))))
|
||||
|
||||
;; ── scheduler loop ──────────────────────────────────────────────
|
||||
;; Each process's entry runs inside a `reset`; `receive` uses `shift`
|
||||
;; to suspend (saving a continuation on the proc record). When a `!`
|
||||
;; delivers a message to a waiting process we re-enqueue it — the
|
||||
;; scheduler step invokes the saved continuation, which retries the
|
||||
;; receive against the updated mailbox.
|
||||
;; Each scheduler step wraps the process body in `guard`. `receive`
|
||||
;; with no match captures a `call/cc` continuation onto the proc
|
||||
;; record and then `raise`s `er-suspend-marker`; the guard catches
|
||||
;; the raise and the scheduler moves on. `exit/1` raises an exit
|
||||
;; marker the same way. Resumption from a saved continuation also
|
||||
;; runs under a fresh `guard` so a resumed receive that needs to
|
||||
;; suspend again has a handler to unwind to. `shift`/`reset` aren't
|
||||
;; usable here because SX's captured delimited continuations don't
|
||||
;; re-establish their own reset boundary when invoked — a second
|
||||
;; suspension during replay raises "shift without enclosing reset".
|
||||
(define er-suspend-marker {:tag "er-suspend-marker"})
|
||||
|
||||
(define
|
||||
@@ -380,15 +382,17 @@
|
||||
(let
|
||||
((prev-k (er-proc-field pid :continuation))
|
||||
(result-ref (list nil)))
|
||||
(if
|
||||
(= prev-k nil)
|
||||
(guard
|
||||
(c
|
||||
((er-suspended? c) (set-nth! result-ref 0 c))
|
||||
((er-exited? c) (set-nth! result-ref 0 c)))
|
||||
(set-nth!
|
||||
result-ref
|
||||
0
|
||||
(reset (er-apply-fun (er-proc-field pid :initial-fun) (list))))
|
||||
(do
|
||||
(er-proc-set! pid :continuation nil)
|
||||
(set-nth! result-ref 0 (prev-k nil))))
|
||||
(if
|
||||
(= prev-k nil)
|
||||
(er-apply-fun (er-proc-field pid :initial-fun) (list))
|
||||
(do (er-proc-set! pid :continuation nil) (prev-k nil)))))
|
||||
(let
|
||||
((r (nth result-ref 0)))
|
||||
(cond
|
||||
|
||||
Reference in New Issue
Block a user