Landin library reference discuss source

compiler/tests/fixtures/runtime/fibre-same-source-any-provider/main.ldn

1--  D444, prototype 5's two requests in miniature: one task waits on a
2--  clock and the other answers at once, from one source.  Over the
3--  blocking host and over fibre.whole each task runs to its end as it is
4--  admitted, so `a` is answered first; over a round of turns, whose clock
5--  takes turns while it waits, `b` is answered while `a` waits.  Each task
6--  records its answer through a pointer to the caller's parameter, which
7--  the group keeps through `escaping into` (D445).
8import core/failure
9import core/fibre
10import core/fibre/stacks
11import core/io
12import core/time
13import hosted/system
14
15answers: type = struct
16    order: [2]u8
17    count: usize
18end answers
19
20asking: type = struct
21    clock: any time.clock
22    wait: u64
23    tag: u8
24    heard: ptr mut answers
25end asking
26
27--  Nothing in it knows it runs on a fibre.
28ask: (inout self: asking) -> none ! failure.reason =
29    if self.wait > 0 then
30        self.clock.sleep(time.milliseconds(self.wait))
31    end if
32    self.heard.val.order[self.heard.val.count] = self.tag
33    self.heard.val.count += 1
34end ask
35
36ask_both: (runs: any fibre.scheduler, clock: any time.clock,
37           inout heard: answers) -> none ! failure.reason =
38    --  A task here takes about 4.4 KiB of its stack on RV64, whose
39    --  frames keep every scalar in a home of their own, at every profile.
40    mut stacks: [2 * 8192]u8 = zeroed
41    mut asks := try fibre.group_over(runs, stacks, 2)
42    defer fibre.join(asks) else none
43    a: asking = (clock: clock, wait: 20, tag: u8('a'), heard: addr heard)
44    try fibre.admit(asks, ask, a)
45    b: asking = (clock: clock, wait: 0, tag: u8('b'), heard: addr heard)
46    try fibre.admit(asks, ask, b)
47    try fibre.join(asks)
48end ask_both
49
50--  A clock whose sleep returns at once, having moved its reading on.
51still: type = struct
52    reading: ptr mut u64
53end still
54
55still_now: (self: still) -> (at: time.instant) =
56    at = time.instant(self.reading.val)
57end still_now
58
59still_sleep: (self: still, span: time.duration) -> none =
60    self.reading.val += u64(span)
61end still_sleep
62
63still is time.clock (now: still_now, sleep: still_sleep)
64
65--  A clock that takes a turn for each millisecond it sleeps: its reading
66--  moves on only while its sleeper waits, and the round's other fibres
67--  run meanwhile.
68turning: type = struct
69    reading: ptr mut u64
70    runs: any fibre.turns
71end turning
72
73turning_now: (self: turning) -> (at: time.instant) =
74    at = time.instant(self.reading.val)
75end turning_now
76
77turning_sleep: (self: turning, span: time.duration) -> none =
78    deadline: u64 = self.reading.val + u64(span)
79    while self.reading.val < deadline do
80        self.runs.yield()
81        self.reading.val += u64(time.milliseconds(1))
82    end while
83end turning_sleep
84
85turning is time.clock (now: turning_now, sleep: turning_sleep)
86
87show: (provider: type is io.writer, inout out: io.buffered_writer(provider),
88       name: []u8, heard: answers) -> none ! io.io_failed =
89    try io.put(out, name)
90    try io.put(out, ": ")
91    try io.put(out, heard.order[0..<heard.count])
92    try io.put(out, "\n")
93end show
94
95--  The same `ask_both` over three providers.
96run: (host: system.host) -> none ! failure.reason =
97    mut storage: [64]u8 = zeroed
98    mut out := io.buffered_over(host, io.out(host), storage)
99    defer io.flush(out) else none
100
101    mut over_host: answers = zeroed
102    try ask_both(any(addr host), any(addr host), over_host)
103    try show(out, "host", over_host)
104
105    runner: fibre.whole = zeroed
106    mut reading: u64 = 0
107    stopped: still = (reading: addr reading)
108    mut over_whole: answers = zeroed
109    try ask_both(any(addr runner), any(addr stopped), over_whole)
110    try show(out, "whole", over_whole)
111
112    mut state: stacks.round_space = zeroed
113    mut entries: [3]usize = zeroed
114    idler: stacks.spin = zeroed
115    round := try stacks.round_over(state, entries, any(addr idler))
116    taking: turning = (reading: addr reading, runs: any(addr round))
117    mut over_round: answers = zeroed
118    try ask_both(any(addr round), any(addr taking), over_round)
119    try show(out, "round", over_round)
120end run
121
122public main: () -> (code: i32) =
123    code = 1
124    host := system.new()
125    run(host) else (problem)
126        _ = problem
127        return
128    end
129    code = 0
130end main