Make blocking socket FFI collect-safe; fix http-client temp-file race

Two thread-safety bugs in the native FFI layer.

The HTTP server's accept/recv/send were plain foreign-procedures. A thread
inside a foreign call stays active for the stop-the-world collector, so the
accept loop sitting idle in accept() froze GC for the whole process whenever
another thread (a future, an async block) allocated. Mark the three blocking
calls __collect_safe so the thread deactivates for the call's duration —
collection proceeds while the accept thread waits. The args are an fd and
foreign-alloc'd buffers (outside the Scheme heap), so a collection mid-call has
nothing to move.

jolt.http-client built its -D header-file path from an unguarded (set! counter
(+ counter 1)) and counter mod 90000, with no per-process component. Concurrent
requests could compute the same path and clobber each other's headers. Use a
mutex-guarded monotonic counter plus the pid.

test/chez/ffi-server-test.ss exercises both (a (collect) while the server is
idle in accept(), temp-path uniqueness across threads, and a live request) and
is wired into the gate as `make ffi`.
This commit is contained in:
Yogthos 2026-06-22 08:12:53 -04:00
parent 4114766c71
commit 6f433a1b3c
4 changed files with 97 additions and 8 deletions

View file

@ -41,11 +41,17 @@
(else n))))
(else (jolt-str-render-one ct))))
;; A per-request header file path, unique across processes (PID) and threads (a
;; mutex-guarded monotonic counter). The previous unguarded `set!` + `mod 90000`
;; raced: concurrent callers could compute the same path and clobber each other's
;; -D header dump. getpid is a fast, non-blocking foreign call.
(define c-getpid (begin (load-shared-object #f) (foreign-procedure "getpid" () int)))
(define hc-tmp-mutex (make-mutex))
(define hc-tmp-counter 0)
(define (hc-tmp-path)
(set! hc-tmp-counter (+ hc-tmp-counter 1))
(string-append (or (getenv "TMPDIR") "/tmp") "/jolt-http-"
(number->string (* 100000 (+ 1 (modulo hc-tmp-counter 90000)))) ".hdr"))
(let ((n (with-mutex hc-tmp-mutex (set! hc-tmp-counter (+ hc-tmp-counter 1)) hc-tmp-counter)))
(string-append (or (getenv "TMPDIR") "/tmp") "/jolt-http-"
(number->string (c-getpid)) "-" (number->string n) ".hdr")))
(define (hc-trim s)
(let* ((n (string-length s))