erlang: exit/1 + process termination (+9 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:
@@ -231,6 +231,22 @@
|
||||
er-proc-mailbox-size
|
||||
(fn (pid) (er-q-len (er-proc-field pid :mailbox))))
|
||||
|
||||
;; Main process is always pid 0 (scheduler starts with next-pid 0 and
|
||||
;; erlang-eval-ast calls er-proc-new! first). Returns nil if no eval
|
||||
;; has run.
|
||||
(define
|
||||
er-main-pid
|
||||
(fn () (er-mk-pid 0)))
|
||||
|
||||
(define
|
||||
er-last-main-exit-reason
|
||||
(fn
|
||||
()
|
||||
(if
|
||||
(er-proc-exists? (er-main-pid))
|
||||
(er-proc-field (er-main-pid) :exit-reason)
|
||||
nil)))
|
||||
|
||||
;; ── process BIFs ────────────────────────────────────────────────
|
||||
(define
|
||||
er-bif-is-pid
|
||||
@@ -272,6 +288,20 @@
|
||||
(dict-set! proc :initial-fun fv)
|
||||
(get proc :pid)))))
|
||||
|
||||
(define
|
||||
er-bif-exit
|
||||
(fn
|
||||
(vs)
|
||||
(cond
|
||||
(= (len vs) 1)
|
||||
(let
|
||||
((reason (nth vs 0)))
|
||||
(shift k (er-mk-exit-marker reason)))
|
||||
(= (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 `!`
|
||||
@@ -288,6 +318,18 @@
|
||||
(= (type-of v) "dict")
|
||||
(= (get v :tag) "er-suspend-marker"))))
|
||||
|
||||
(define
|
||||
er-exited?
|
||||
(fn
|
||||
(v)
|
||||
(and
|
||||
(= (type-of v) "dict")
|
||||
(= (get v :tag) "er-exit-marker"))))
|
||||
|
||||
(define
|
||||
er-mk-exit-marker
|
||||
(fn (reason) {:tag "er-exit-marker" :reason reason}))
|
||||
|
||||
(define
|
||||
er-sched-run-all!
|
||||
(fn
|
||||
@@ -351,6 +393,12 @@
|
||||
((r (nth result-ref 0)))
|
||||
(cond
|
||||
(er-suspended? r) nil
|
||||
(er-exited? r)
|
||||
(do
|
||||
(er-proc-set! pid :state "dead")
|
||||
(er-proc-set! pid :exit-reason (get r :reason))
|
||||
(er-proc-set! pid :exit-result nil)
|
||||
(er-proc-set! pid :continuation nil))
|
||||
:else (do
|
||||
(er-proc-set! pid :state "dead")
|
||||
(er-proc-set! pid :exit-reason (er-mk-atom "normal"))
|
||||
|
||||
@@ -400,6 +400,38 @@
|
||||
(ev "Me = self(), Me ! first, Me ! second, X = receive second -> got_second after 0 -> to end, Y = receive first -> got_first after 0 -> to end, {X, Y}")
|
||||
(er-mk-tuple (list (er-mk-atom "got_second") (er-mk-atom "got_first"))))
|
||||
|
||||
;; ── exit/1 + process termination ─────────────────────────────────
|
||||
(er-eval-test "exit normal returns nil" (ev "exit(normal)") nil)
|
||||
(er-eval-test "exit normal reason"
|
||||
(do (ev "exit(normal)") (nm (er-last-main-exit-reason))) "normal")
|
||||
(er-eval-test "exit bye reason"
|
||||
(do (ev "exit(bye)") (nm (er-last-main-exit-reason))) "bye")
|
||||
(er-eval-test "exit tuple reason"
|
||||
(do (ev "exit({shutdown, crash})")
|
||||
(get (er-last-main-exit-reason) :tag))
|
||||
"tuple")
|
||||
(er-eval-test "normal completion reason"
|
||||
(do (ev "42") (nm (er-last-main-exit-reason))) "normal")
|
||||
(er-eval-test "exit aborts subsequent"
|
||||
(do (er-io-flush!) (ev "io:format(\"a~n\"), exit(bye), io:format(\"b~n\")") (er-io-buffer-content))
|
||||
"a\n")
|
||||
(er-eval-test "child exit doesn't kill parent"
|
||||
(do
|
||||
(er-io-flush!)
|
||||
(ev "spawn(fun () -> io:format(\"before~n\"), exit(quit), io:format(\"after~n\") end), io:format(\"main~n\")")
|
||||
(er-io-buffer-content))
|
||||
"main\nbefore\n")
|
||||
(er-eval-test "child exit reason recorded on child"
|
||||
(do
|
||||
(er-io-flush!)
|
||||
(ev "P = spawn(fun () -> exit(child_bye) end), io:format(\"~p\", [is_pid(P)])")
|
||||
(er-io-buffer-content))
|
||||
"true")
|
||||
(er-eval-test "exit inside fn chain"
|
||||
(do (ev "F = fun () -> exit(from_fn) end, F()")
|
||||
(nm (er-last-main-exit-reason)))
|
||||
"from_fn")
|
||||
|
||||
(define
|
||||
er-eval-test-summary
|
||||
(str "eval " er-eval-test-pass "/" er-eval-test-count))
|
||||
|
||||
@@ -564,6 +564,7 @@
|
||||
(= name "is_pid") (er-bif-is-pid vs)
|
||||
(= name "self") (er-bif-self vs)
|
||||
(= name "spawn") (er-bif-spawn vs)
|
||||
(= name "exit") (er-bif-exit vs)
|
||||
:else (error
|
||||
(str "Erlang: undefined function '" name "/" (len vs) "'")))))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user