Real Thread/yield + Thread/interrupted (jolt-l2gc)

Thread/yield was a no-op and Thread/interrupted always returned false. Now:

- yield calls libc sched_yield (resolved once via the process symbols), so a
  spin loop relinquishes the CPU. Falls back to a zero-length park if the symbol
  can't be resolved.
- each OS thread carries an interrupt flag (a box, thread-local). currentThread
  returns a handle wrapping the calling thread's flag, so .interrupt from another
  thread sets the target's flag. .isInterrupted reads without clearing; the static
  Thread/interrupted reads and clears — JVM semantics.

Consolidates the Thread surface: currentThread + the instance methods live in
io.ss (where the handle and its classloader are built), the flag box + yield +
the interrupted static in host-static.ss. Unit cases cover yield, the read/clear
split, and a cross-thread interrupt over a future.
This commit is contained in:
Yogthos 2026-06-23 00:06:04 -04:00
parent 87aec859b8
commit 980ec73933
4 changed files with 59 additions and 14 deletions

View file

@ -369,13 +369,22 @@
(if (jolt-nil? u) jolt-nil (host-new "StringReader" (jolt-slurp (url-strip-scheme (url-spec u))))))))))
(register-class-statics! "ClassLoader" (list (cons "getSystemClassLoader" (lambda () the-classloader))))
(register-class-statics! "java.lang.ClassLoader" (list (cons "getSystemClassLoader" (lambda () the-classloader))))
;; Thread/currentThread -> a thread jhost whose getContextClassLoader is the loader.
(define the-thread (make-jhost "thread" (vector)))
;; Thread/currentThread -> a fresh thread jhost wrapping THIS thread's interrupt
;; flag (the box from current-interrupt-box, host-static.ss), so .interrupt from
;; any thread sets the target thread's flag and .isInterrupted reads it without
;; clearing (instance semantics; the static Thread/interrupted reads-and-clears).
;; getContextClassLoader hands back the loader.
(register-host-methods! "thread"
(list (cons "getContextClassLoader" (lambda (self) the-classloader))
(cons "getName" (lambda (self) "main"))))
(register-class-statics! "Thread" (list (cons "currentThread" (lambda () the-thread))))
(register-class-statics! "java.lang.Thread" (list (cons "currentThread" (lambda () the-thread))))
(cons "getName" (lambda (self) "main"))
(cons "interrupt" (lambda (self)
(when (box? (jhost-state self)) (set-box! (jhost-state self) #t))
jolt-nil))
(cons "isInterrupted" (lambda (self)
(and (box? (jhost-state self)) (unbox (jhost-state self)) #t)))))
(define (current-thread-handle) (make-jhost "thread" (current-interrupt-box)))
(register-class-statics! "Thread" (list (cons "currentThread" current-thread-handle)))
(register-class-statics! "java.lang.Thread" (list (cons "currentThread" current-thread-handle)))
;; --- java.io.File / java.util.UUID constructors -----------------------------
;; (java.io.File. parent child) joins with "/"; (File. path) wraps the path.