v0.19: port std/os signals #1484

Merged
fare merged 5 commits from jay/gerbil:v0.19-signal into v0.19-staging 2026-09-07 19:20:32 +00:00
Member

Ports the remaining signal-handling modules to v0.19 under :std/os, including signal, signalfd, signal-handler, and kqueue.

Warning

LLM-assisted with gerbil-mcp

Ports the remaining signal-handling modules to v0.19 under `:std/os`, including `signal`, `signalfd`, `signal-handler`, and `kqueue`. > [!WARNING] > LLM-assisted with `gerbil-mcp`
jay changed title from WIP: v0.19: port std/os signals to v0.19: port std/os signals 2026-09-04 21:29:53 +00:00
jay requested review from Owners 2026-09-04 21:30:02 +00:00
jay force-pushed v0.19-signal from 0583d874a9 to 05eb73415a 2026-09-04 21:34:24 +00:00 Compare
vyzo left a comment

this looks impressively good, but i'll have to do a thorough pass. Spotted an issue at first pass.

Have you run the tests in bsd/darwin? I only have linux boxes so i can't verify those tests.

this looks impressively good, but i'll have to do a thorough pass. Spotted an issue at first pass. Have you run the tests in bsd/darwin? I only have linux boxes so i can't verify those tests.
@ -0,0 +90,4 @@
(let (count (device-read device buffer 0 (u8vector-length buffer)))
(cond
((fxnegative? count)
(device-wait-input! device !NoTimeout))
Owner

shouldn't we loop back after device-wait-input! return. missing a (wait-loop) call.

shouldn't we loop back after device-wait-input! return. missing a (wait-loop) call.
Author
Member

wait-loop is on line 107, outside the cond

wait-loop is on line 107, outside the cond
Author
Member

@vyzo wrote in #1484 (comment):

Have you run the tests in bsd/darwin? I only have linux boxes so i can't verify those tests.

My work computer is a mac, lemme try it there. will report back

@vyzo wrote in https://git.cons.io/mighty-gerbils/gerbil/pulls/1484#issuecomment-2617: > Have you run the tests in bsd/darwin? I only have linux boxes so i can't verify those tests. My work computer is a mac, lemme try it there. will report back
fare approved these changes 2026-09-06 18:53:01 +00:00
Dismissed
fare left a comment

Looks overall good to me, but I have a few concerns that I believe deserve comments in the code at least—if not in this PR, in a quick follow-up.

Looks overall good to me, but I have a few concerns that I believe deserve comments in the code at least—if not in this PR, in a quick follow-up.
@ -0,0 +13,4 @@
./signalfd)
(export signalfd-test)
(def signalfd-test
Owner

My clanker friend GPT 5.6 Sol (High) says:

This test isn't SMP-safe as currently written. sigprocmask only blocks SIGHUP in the calling thread, while kill(getpid(), SIGHUP) may deliver it to any unblocked runtime thread; with the default disposition this can simply kill gxtest. 0583d874a9 seems to have fixed exactly this by blocking before fork/exec, but that commit disappeared in the force-push. Was that intentional? I think we need that setup (or equivalent) back.

My clanker friend GPT 5.6 Sol (High) says: This test isn't SMP-safe as currently written. `sigprocmask` only blocks SIGHUP in the calling thread, while `kill(getpid(), SIGHUP)` may deliver it to any unblocked runtime thread; with the default disposition this can simply kill gxtest. 0583d874a9 seems to have fixed exactly this by blocking before fork/exec, but that commit disappeared in the force-push. Was that intentional? I think we need that setup (or equivalent) back.
@ -0,0 +70,4 @@
(:- device OSDevice)
write-fd
(make-mutex 'signal-handler))
(spawn/name 'signal-handler signal-handler-wait self)
Owner

Clanker says:

Have we considered the state of this machinery across fork? The child inherits the installed signal dispositions and the pipe FDs, but not this signal-handler thread. So until exec, a registered signal can be caught by ffi_signal_dispatch in the child but can never be dispatched there; a wake byte would also go to the inherited pipe.

Maybe Gambit only gives us a fork→exec window where this is harmless, but it seems worth checking whether fork-and-continue is supported anywhere.

Of course, to make things more interesting, the situation will be different with green threads vs actual SMP. At least a TODO is required. @vyzo care to comment?

Clanker says: > Have we considered the state of this machinery across `fork`? The child inherits the installed signal dispositions and the pipe FDs, but not this signal-handler thread. So until `exec`, a registered signal can be caught by `ffi_signal_dispatch` in the child but can never be dispatched there; a wake byte would also go to the inherited pipe. > > Maybe Gambit only gives us a fork→exec window where this is harmless, but it seems worth checking whether fork-and-continue is supported anywhere. Of course, to make things more interesting, the situation will be different with green threads vs actual SMP. At least a TODO is required. @vyzo care to comment?
Owner

i agree, this is problematic. this needs to run on all threads, with on-all-processors that used to be in the now defunct std/misc/threads. I think we need to ressurect this in std/sync/smp and have the on-all-processors procedure there.

i agree, this is problematic. this needs to run on all threads, with on-all-processors that used to be in the now defunct std/misc/threads. I think we need to ressurect this in std/sync/smp and have the on-all-processors procedure there.
Owner

we can also do with a TODO here, but i would prefer to resolve this as it is a real issue.

we can also do with a TODO here, but i would prefer to resolve this as it is a real issue.
Owner

seems we are going to ressurect some more stuff from that module as i am working on porting the remaining on std (std/net/repl uses some). i will put them in std/sync/threads, we can leave a big fat TODO in this pr for now.

seems we are going to ressurect some more stuff from that module as i am working on porting the remaining on std (std/net/repl uses some). i will put them in std/sync/threads, we can leave a big fat TODO in this pr for now.
@ -0,0 +359,4 @@
(:- (kevent-ident events i) :fixnum))))
(when event-handler
(signal-handler-dispatch
(:- event-handler :procedure)))))
Owner

Clanker says (after I corrected its suggestion):

BSD signal multiplicity:

EVFILT_SIGNAL gives us the number of occurrences since the previous kevent in data, but we currently discard that information and invoke the Scheme handler with no indication of multiplicity.

I don't think we necessarily want to call the handler N times: the usual signal-handling protocol is for the handler to treat the signal as a notification and drain whatever underlying state is available, rather than assume one notification corresponds to one event. (SIGCHLD is the obvious example.)

Still, should the event-handler API expose the multiplicity here, or at least should we leave a TODO noting that kqueue gives us information that the current abstraction discards?

Clanker says (after I corrected its suggestion): > BSD signal multiplicity: > > `EVFILT_SIGNAL` gives us the number of occurrences since the previous `kevent` in `data`, but we currently discard that information and invoke the Scheme handler with no indication of multiplicity. > > I don't think we necessarily want to call the handler N times: the usual signal-handling protocol is for the handler to treat the signal as a notification and drain whatever underlying state is available, rather than assume one notification corresponds to one event. (`SIGCHLD` is the obvious example.) > > Still, should the event-handler API expose the multiplicity here, or at least should we leave a `TODO` noting that kqueue gives us information that the current abstraction discards?
@ -0,0 +381,4 @@
((vector-ref handlers signo)
(vector-set! handlers signo thunk))
(else
(ignore-signal! sh signo)
Owner

Clanker friend says of FreeBSD (as contrasted to other BSDs):

FreeBSD has a nasty EVFILT_SIGNAL exception here: unlike other signals, SIGCHLD is not reported by kqueue when its disposition is SIG_IGN. Since ignore-signal! is unconditional, add-signal-handler! SIGCHLD won't work on FreeBSD.

This appears inherited from the old implementation rather than introduced here, but this seems like the right time to fix/test it. Perhaps SIGCHLD needs a no-op handler rather than SIG_IGN on FreeBSD.

I'd say this deserves at the very least a "TODO" comment. And I don't think no-op should be it—some kind of wait() and handling of subprocess record would be more appropriate—through a user-overridable hook, I suppose.

Clanker friend says of FreeBSD (as contrasted to other BSDs): > FreeBSD has a nasty `EVFILT_SIGNAL` exception here: unlike other signals, `SIGCHLD` is *not* reported by `kqueue` when its disposition is `SIG_IGN`. Since `ignore-signal!` is unconditional, `add-signal-handler! SIGCHLD` won't work on FreeBSD. > > This appears inherited from the old implementation rather than introduced here, but this seems like the right time to fix/test it. Perhaps `SIGCHLD` needs a no-op handler rather than `SIG_IGN` on FreeBSD. I'd say this deserves at the very least a "TODO" comment. And I don't think no-op should be it—some kind of wait() and handling of subprocess record would be more appropriate—through a user-overridable hook, I suppose.
Restore inherited-mask signalfd testing: process-directed signals can reach other unblocked native threads. Record the deferred fork, BSD multiplicity, and FreeBSD SIGCHLD concerns requested in review.
jay requested reviews from fare, vyzo 2026-09-07 18:33:18 +00:00
fare approved these changes 2026-09-07 19:20:24 +00:00
fare merged commit acef95bf60 into v0.19-staging 2026-09-07 19:20:32 +00:00
fare referenced this pull request from a commit 2026-09-07 19:20:33 +00:00
Owner

@vyzo what is the follow-up plan? Create an issue? Add a - [ ] box to an existing issue/TODO ? To be done immediately by your clanker?

@vyzo what is the follow-up plan? Create an issue? Add a - [ ] box to an existing issue/TODO ? To be done immediately by your clanker?
Owner

let's create an issue so that we don't forget. SMP will land in the not so distant future.

let's create an issue so that we don't forget. SMP will land in the not so distant future.
vyzo deleted branch v0.19-signal 2026-09-07 19:48:06 +00:00
Sign in to join this conversation.
No description provided.