compiler/tests/fixtures/runtime/signals-fake-firmware/main.ldn
skip to the library navigation
1-- D449, D477: core/io/fake's signals over a round of turns, within a
2-- 32 KiB firmware image. A fibre written against `any signal.signals`
3-- watches SIGUSR1 and SIGTERM and waits for each in turn; another fibre
4-- takes a turn and then raises SIGUSR1, SIGHUP, which nobody watches and
5-- is dropped, and SIGTERM twice, the second while the first waits to be
6-- read and so one event with it. The waiter hears SIGUSR1 and then
7-- SIGTERM, each with the number the fake gives it. Last, a fibre
8-- waiting for a signal is woken by `stop_watching`, its wait failing
9-- `io_failed`.
10import core/failure
11import core/fibre
12import core/fibre/stacks
13import core/io
14import core/io/fake
15import core/io/signal
16
17-- What the waiter heard: each signal's number, in order, and `s` when a
18-- wait failed because watching stopped.
19mut heard: [8]u32 = zeroed
20mut count: usize = 0
21
22note: (number: u32) -> none =
23 heard[count] = number
24 inc count
25end note
26
27-- Every task's state, one type so the group's `admit` is one routine in
28-- the image: the source as any provider of signals, and as the fake a
29-- test raises signals into.
30waiting: type = struct
31 signals: any signal.signals
32 source: fake.signals
33end waiting
34
35-- Hear signals until SIGTERM. Nothing in it knows the source is a fake.
36until_terminate: (inout state: waiting) -> none ! failure.reason =
37 try state.signals.watch(signal.user1)
38 try state.signals.watch(signal.terminate)
39 loop do
40 received: signal.event = try state.signals.next_signal()
41 note(received.number)
42 break when received.which == signal.terminate
43 end loop
44end until_terminate
45
46-- Take a turn, so the waiter waits first, and raise four signals.
47raise_four: (inout state: waiting) -> none ! failure.reason =
48 fibre.yield(state.source)
49 fake.raise(state.source, signal.user1)
50 fake.raise(state.source, signal.hangup)
51 fake.raise(state.source, signal.terminate)
52 fake.raise(state.source, signal.terminate)
53end raise_four
54
55-- Wait for a signal that never comes.
56wait_in_vain: (inout state: waiting) -> none ! failure.reason =
57 try state.signals.watch(signal.hangup)
58 received: signal.event = state.signals.next_signal() else (problem)
59 if problem == io.io_failed then note(0) end if
60 return
61 end
62 _ = received
63end wait_in_vain
64
65-- Module storage, so the stacks are no frame's: Cortex-M0's reset stack
66-- is 4 KiB, and its 12 KiB of RAM below that hold two stacks of 4 KiB.
67fixed if compiler.word_size == 32 then
68 mut backing: [2 * 4096]u8 = zeroed
69else
70 mut backing: [2 * 8192]u8 = zeroed
71end if
72
73run: (signals: fake.signals, counts: ptr fake.signals_space)
74 -> none ! failure.reason =
75 runs: any fibre.turns = any(addr signals)
76 mut tasks := try fibre.turns_over(runs, backing, 2)
77 defer fibre.join(tasks) else none
78 parts: waiting = (signals: any(addr signals), source: signals)
79 try fibre.admit(tasks, until_terminate, parts)
80 try fibre.admit(tasks, raise_four, parts)
81 try fibre.join(tasks)
82 fail io.io_failed when counts.val.raised <> 4
83 or counts.val.ignored <> 1 or counts.val.delivered <> 2
84 or counts.val.turns == 0
85 try fibre.admit(tasks, wait_in_vain, parts)
86 fibre.yield(signals)
87 try signal.stop_watching(signals)
88 try fibre.join(tasks)
89end run
90
91public main: () -> (code: i32) =
92 code = 1
93 mut state: stacks.round_space = zeroed
94 mut entries: [3]usize = zeroed
95 idler: stacks.spin = zeroed
96 round := stacks.round_over(state, entries, any(addr idler)) else (problem)
97 _ = problem
98 return
99 end
100 mut space: fake.signals_space = zeroed
101 signals := fake.signals_over(space, any(addr round))
102 run(signals, addr space) else (problem)
103 _ = problem
104 return
105 end
106 code = 2
107 return when count <> 3 or heard[0] <> 10 or heard[1] <> 15
108 or heard[2] <> 0
109 code = 42
110end main