Chez concurrency pt.1: real OS-thread futures + blocking promises (shared heap)
future/future-call run the body on a native thread (fork-thread) over the SAME heap — JVM semantics, not Janet's isolated-heap snapshot. deref blocks on a mutex+condition latch; timed (deref f ms val) uses an absolute deadline. promise is a real blocking promise (deref parks until deliver), replacing the Janet non-blocking atom shim. future?/future-done?/future-cancelled?/future-cancel /realized? are native (the overlay versions read Janet map keys); re-asserted in post-prelude over the overlay. pmap/pcalls/pvalues (overlay, over future) light up for free. Thread-safety this forces: - atoms get a per-atom mutex; swap!/swap-vals! are a JVM-style CAS loop (f runs outside the lock, so a watch/validator can deref the same atom); reset!/ compare-and-set! are atomic. - the dynamic binding stack becomes a Chez thread-parameter, so each future/thread has its own; Chez inherits it at fork, giving binding conveyance (the shim also installs an explicit snapshot). - Thread/sleep really sleeps now (a worker sleeping doesn't block the parent). Re-minted the seed: future-call now resolves at compile time, so pmap compiles to a var-deref instead of the host-static-call fallback that crashed. image.ss unchanged. Corpus: the 2 snapshot cases now match the JVM (shared) not Janet (isolated) — allowlisted on both Chez gates; the two racy future-cancel cases allowlisted; "promise undelivered" (blocks on JVM/Chez, profile :bucket :timeout) skipped like :throws. Zero-Janet corpus 2544 -> 2569, 0 new divergences, floor raised. Full Janet gate + JVM cert green. jolt-byjr
This commit is contained in:
parent
a23095b502
commit
ec30c9e405
10 changed files with 330 additions and 42 deletions
|
|
@ -15,11 +15,15 @@
|
|||
;; the stack before falling back to the cell root. Loaded LAST (after vars.ss and
|
||||
;; ns.ss) so it chains the fully-extended jolt-var-get and overrides rt.ss var-deref.
|
||||
|
||||
(define dyn-binding-stack '())
|
||||
;; THREAD-LOCAL (jolt-byjr): a Chez thread parameter, so each OS thread (a future
|
||||
;; / go block) has its own binding stack. Chez initializes a new thread's parameter
|
||||
;; to the spawning thread's value at fork time, giving Clojure binding conveyance
|
||||
;; for free (the future shim also installs an explicit snapshot, belt-and-suspenders).
|
||||
(define dyn-binding-stack (make-thread-parameter '()))
|
||||
|
||||
;; find the innermost (cell . value) pair binding CELL, or #f.
|
||||
(define (dyn-find-binding cell)
|
||||
(let loop ((frames dyn-binding-stack))
|
||||
(let loop ((frames (dyn-binding-stack)))
|
||||
(and (pair? frames)
|
||||
(or (assq cell (car frames))
|
||||
(loop (cdr frames))))))
|
||||
|
|
@ -28,7 +32,7 @@
|
|||
;; value happens to be jolt-nil.
|
||||
(define dyn-no-binding (list 'no-binding))
|
||||
(define (dyn-binding-value cell)
|
||||
(if (pair? dyn-binding-stack)
|
||||
(if (pair? (dyn-binding-stack))
|
||||
(let ((p (dyn-find-binding cell)))
|
||||
(if p
|
||||
(let ((val (cdr p)))
|
||||
|
|
@ -39,21 +43,21 @@
|
|||
;; push-thread-bindings: frame is a jolt map of var-cell -> value. Fold it into an
|
||||
;; identity-keyed alist of mutable pairs and push.
|
||||
(define (jolt-push-thread-bindings frame)
|
||||
(set! dyn-binding-stack
|
||||
(cons (pmap-fold frame (lambda (k v acc) (cons (cons k v) acc)) '())
|
||||
dyn-binding-stack))
|
||||
(dyn-binding-stack
|
||||
(cons (pmap-fold frame (lambda (k v acc) (cons (cons k v) acc)) '())
|
||||
(dyn-binding-stack)))
|
||||
jolt-nil)
|
||||
|
||||
(define (jolt-pop-thread-bindings)
|
||||
(when (pair? dyn-binding-stack)
|
||||
(set! dyn-binding-stack (cdr dyn-binding-stack)))
|
||||
(when (pair? (dyn-binding-stack))
|
||||
(dyn-binding-stack (cdr (dyn-binding-stack))))
|
||||
jolt-nil)
|
||||
|
||||
;; get-thread-bindings: a jolt map of every currently-bound cell -> value,
|
||||
;; innermost wins. Merge oldest-frame-first (the stack head is innermost). The
|
||||
;; result can be re-pushed by with-bindings* / bound-fn*.
|
||||
(define (jolt-get-thread-bindings)
|
||||
(let loop ((frames (reverse dyn-binding-stack)) (m (jolt-hash-map)))
|
||||
(let loop ((frames (reverse (dyn-binding-stack))) (m (jolt-hash-map)))
|
||||
(if (null? frames)
|
||||
m
|
||||
(loop (cdr frames)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue