Landin library reference discuss source

core/io/signal/signal.ldn

1--  Signals as events (D449, D477): the concept a provider that takes
2--  turns supplies when it delivers the system's signals to a fibre that
3--  waits for them, the portable names of the signals a server cares
4--  about, and what one arrival is.  A signal never runs a handler of
5--  Landin code: the provider reads it, through signalfd on Linux and an
6--  EVFILT_SIGNAL filter of kqueue on Darwin and FreeBSD, as it reads any
7--  other event, and wakes the fibre that waits.  It is a module beneath
8--  core/io, as core/io/fake is, because the concept refines
9--  `fibre.turns` and core/fibre already reaches core/io through
10--  core/failure (D482).
11
12import core/fibre
13import core/io
14
15--- The terminal's interrupt, SIGINT: someone pressed Ctrl-C.
16public interrupt: atom
17--- A request to end, SIGTERM: what a service manager sends to stop a
18--- server, and what `kill` sends when it is not told otherwise.
19public terminate: atom
20--- The controlling terminal has gone, SIGHUP; a daemon, which has none,
21--- commonly takes it to read its configuration again.
22public hangup: atom
23--- A child process ended, stopped or went on, SIGCHLD.
24public child: atom
25--- The first signal left to programs, SIGUSR1.
26public user1: atom
27--- The second signal left to programs, SIGUSR2.
28public user2: atom
29
30--- The signals a provider of `signals` delivers, by portable names: each
31--- system numbers them its own way, and a program that names one here
32--- means the same signal on every system.
33public kind: type = interrupt | terminate | hangup | child | user1 | user2
34
35--- One arrival of a watched signal: its portable name and the number the
36--- system gave it, as a log or `kill` would show it.
37public event: type = struct
38    which: kind
39    number: u32
40end event
41
42--- A provider that delivers signals to a fibre as events (D449). Only a
43--- provider of `fibre.turns` supplies it (D477): a fibre waiting for a
44--- signal lets the provider's other fibres run, where over a provider that
45--- runs each task to its end it would hold the program before it served
46--- anything. A program that waits for a signal asks for `signals`, and
47--- over the blocking host it cannot be written, so a signal there keeps
48--- the system's default disposition: SIGTERM ends the process.
49---
50--- `watch` takes a signal from the system's default disposition and
51--- delivers it as an event from then on. `next_signal` waits as a receive
52--- does, taking turns, for the next arrival of a watched signal; each
53--- arrival is read once, by one waiter, and two arrivals of one signal
54--- before it is read may be one event, as the systems' own queues keep
55--- them. `stop_watching` gives every watched signal back to its default
56--- disposition and wakes every fibre waiting in `next_signal`, whose call
57--- fails `io_failed`, which is how a program stops the fibre that waits
58--- (D449). `next_signal` is the only entry that may switch.
59public signals: type = concept (provider: type) is fibre.turns
60    --- Deliver `which` as an event from now on.
61    watch: (self: provider, which: kind) -> none ! io.io_failed
62    --- Wait, taking turns, for the next arrival of a watched signal.
63    next_signal: (self: provider) -> (received: event) ! io.io_failed
64    --- Give every watched signal back to its default disposition, and
65    --- wake every waiter, failing its call.
66    stop_watching: (self: provider) -> none ! io.io_failed
67end signals
68
69--- Deliver `which` as an event through `signals` evidence.
70public watch: (provider: type is signals, host: provider, which: kind)
71              -> none ! io.io_failed =
72    try provider.watch(host, which)
73end watch
74
75--- Wait, taking turns, for the next arrival of a watched signal.
76public next_signal: (provider: type is signals, host: provider)
77                    -> (received: event) ! io.io_failed =
78    received = try provider.next_signal(host)
79end next_signal
80
81--- Stop delivering signals as events, and wake every fibre waiting for
82--- one, whose call fails `io_failed`.
83public stop_watching: (provider: type is signals, host: provider)
84                      -> none ! io.io_failed =
85    try provider.stop_watching(host)
86end stop_watching