Signal
Signal module: register deferred handlers for OS signals.
A watcher is a zero-argument function () -> () invoked after the signal is delivered, on a normal green-thread stack (deferred green-thread dispatch) — never in async-signal context, so the handler may allocate, log, spawn tasks, and touch shared state freely. There is at most ONE watcher per signal; registering a second replaces the first.
Delivery latency is best-effort (up to ~1s): the runtime flips an atomic pending flag in signal context and drains it from the scheduler / event loop. Repeated deliveries before a drain coalesce into a single handler call.
Term / Int (SIGTERM / SIGINT) special case: while a watcher is registered the first delivery runs the handler and suppresses the default graceful shutdown, giving the program a chance to clean up on its own terms. A second delivery escapes the watcher and forces graceful shutdown (the Ctrl-C-twice escape hatch). Hup / Usr1 / Usr2 have no default action while watched, and their default OS disposition is restored on unwatch.
Example:
Signal.watch(Signal.Term, fn ->
Log.info("shutting down gracefully")
drain_connections()
end)(Post-7.1 the short fn -> body zero-arg spelling works; fn () -> body and fn _ -> body are also accepted.)
Types
Functions
Send sig to the current process — the symmetric trigger for watch.
Signal.raise(Signal.Usr2)
Useful for self-scheduled work and for exercising watchers in tests. The
delivery is asynchronous: a registered watcher runs from the next scheduler
drain, not synchronously at the call site.Remove the watcher for sig, restoring the signal's default disposition.
Signal.unwatch(Signal.Usr1)
Safe to call when no watcher is registered.Register handler to run when sig is delivered.
Signal.watch(Signal.Usr1, fn -> reload_config() end)
The handler runs later, from the scheduler drain, on a normal stack. At
most one watcher exists per signal; a second `watch` replaces the first.
For `Term`/`Int`, registering a watcher suppresses the default shutdown on
the first delivery (a second delivery forces it).