Real nREPL interrupt + thread-local *ns* (jolt-amzy, jolt-6rld)

Two nREPL divergences the library shakeout surfaced — both have a real host
mechanism on Chez.

Interrupt (jolt-amzy): Chez's engine timer (set-timer + thread-local
timer-interrupt-handler) is polled at procedure-call / loop back-edges, so a
running computation — even a tight loop — can be aborted from another thread.
concurrency.ss adds jolt.host/{make-interrupt, interrupt!, run-interruptible}: an
interrupt token is a shared box; run-interruptible arms a periodic timer whose
handler escapes (call/cc) when the token is set, throwing {:jolt/interrupted true}.
The eval thread is reused, not abandoned. (A thread blocked in a __collect_safe
foreign call only sees it on return — like the JVM not killing native code.)

Thread-local *ns* (jolt-6rld): chez-current-ns is now a Chez thread-parameter, so
each session worker / future has its own current ns (vars stay global, only the
pointer is per-thread). *ns* reads derive from it (dyn-binding.ss), and a bound
*ns* drives chez-current-ns — so (binding [*ns* the-ns] (load-string code))
resolves against the-ns, and concurrent in-ns across threads don't clobber each
other. Single-threaded behaviour is unchanged. All runtime .ss — no re-mint.
This commit is contained in:
Yogthos 2026-06-22 18:57:16 -04:00
parent f30a517cf7
commit c18f8087f0
6 changed files with 79 additions and 8 deletions

View file

@ -111,8 +111,9 @@
;; redirect them. It is enough for *ns* / str-of-ns to track the switch.
(define (jolt-in-ns desig)
(let* ((nm (ns-desig->name desig)) (n (intern-ns! nm)))
;; set the THREAD-LOCAL current ns; *ns* reads derive from it (dyn-binding.ss),
;; so this is per-thread — concurrent nREPL sessions don't clobber each other.
(set-chez-ns! nm)
(def-var! "clojure.core" "*ns*" n)
n))
;; ns-name: a namespace's name as a (no-ns) symbol. Overrides the overlay (which