use @getpid[I32]()
use @kill[I32](pid_t: I32, sig: U32)
use @raise[I32](sig: U32)
primitive SignalSubscriberLimit
"""
The per-signal subscriber limit (16) was already reached. A later
registration for the same signal can succeed once a current subscriber
unsubscribes.
"""
primitive SignalRegistrationRefused
"""
The operating system refused the registration. Retrying will not
succeed.
"""
type SignalRegistrationError is
(SignalSubscriberLimit | SignalRegistrationRefused)
"""
Why a `SignalHandler`'s registration could not be completed.
"""
interface SignalNotify
"""
Notifications for a signal.
"""
fun ref apply(count: U32): Bool =>
"""
Called with the number of times the signal has fired since this was
last called. Return false to stop listening for the signal.
Delivery batching differs by platform: on Linux, macOS, and the BSDs
several firings that arrive close together can be reported in one call
with `count` greater than one, while on Windows each firing is a
separate call with a `count` of one.
"""
true
fun ref registration_failed(reason: SignalRegistrationError) =>
"""
Called when the handler's registration could not be completed.
`SignalSubscriberLimit` is transient — a slot may open once another
subscriber unsubscribes; `SignalRegistrationRefused` is permanent, so
re-registering the same signal will fail again. The handler is then
disposed — `disposed` follows once the runtime confirms it, and `apply`
will not have run. If the handler was explicitly disposed before the
failure was delivered, only `disposed` is called.
"""
None
fun ref disposed() =>
"""
Called when the runtime has finished unregistering the handler,
whichever way disposal began: explicitly via `SignalHandler.dispose`,
when `apply` returned false, or when the registration could not be
completed (preceded by `registration_failed` in that case). `apply`
will never be called after this.
By the time this is called, the handler no longer affects signal
delivery: if it was the signal's last subscriber, the signal's
disposition from before it was first handled has been restored. For
most signals that is the operating system default, so raising a
terminating one from here ends the process; for a signal the runtime
keeps ignored, such as SIGPIPE, it is SIG_IGN. A handler disposed while
the runtime itself is shutting down may never receive this call.
"""
None
primitive SignalRaise
"""
Raise a signal.
Unlike SignalHandler, this accepts a raw signal number rather than a
HandleableSignal. Raising fatal signals (e.g. SIGABRT to intentionally crash)
is a legitimate operation — it is only handling them via the ASIO
mechanism that is prevented.
The raise is process-wide: every currently subscribed handler for the
signal is notified. With no subscribers, the signal's current disposition
applies — the operating system default for most signals (process death for
a terminating one), but SIG_IGN for one the runtime keeps ignored like
SIGPIPE.
"""
fun apply(auth: SignalAuth, sig: U32) =>
ifdef osx then
// On Darwin, @raise delivers the signal to the current thread, not the
// process, but kqueue EVFILT_SIGNAL will only see signals delivered to
// the process. @kill delivers the signal to a specific process.
@kill(@getpid(), sig)
else
@raise(sig)
end