Landin library reference discuss source

compiler/tests/fixtures/runtime/network-fake-turns-exchange/main.ldn

1--  D449: core/io/fake's network over a round of turns.  A server fibre
2--  accepts a connection and answers what it receives, and a client fibre
3--  connects, sends and receives the answer, each written as it would be
4--  over a real network.  Where a call would wait it takes a turn instead,
5--  so the exchange completes in either order of start: with the server
6--  first, its accept and the client's receive each wait one turn; with the
7--  client first, only the client's receive does.
8import core/cmp
9import core/failure
10import core/fibre
11import core/fibre/stacks
12import core/io
13import core/io/fake
14import core/net
15
16--  The order things happened in: `a` the server accepted, `r` it received
17--  the request, `c` the client connected and `d` the client read the
18--  answer.
19mut trace: [8]u8 = zeroed
20mut marks: usize = 0
21
22mark: (letter: u8) -> none =
23    trace[marks] = letter
24    inc marks
25end mark
26
27party: type = struct
28    network: fake.network
29    listener: io.file
30    to: net.address
31end party
32
33serve: (inout state: party) -> none ! failure.reason =
34    connection: io.file = try net.accept(state.network, state.listener)
35    defer net.close_socket(state.network, connection) else none
36    mark(u8('a'))
37    mut buffer: [8]u8 = zeroed
38    got: usize = try net.receive(state.network, connection, buffer)
39    fail io.io_failed when cmp.compare(buffer[0..<got], "ping") <> cmp.equal
40    mark(u8('r'))
41    try net.send(state.network, connection, "pong")
42end serve
43
44call: (inout state: party) -> none ! failure.reason =
45    connection: io.file = try net.connect(state.network, state.to)
46    defer net.close_socket(state.network, connection) else none
47    mark(u8('c'))
48    try net.send(state.network, connection, "ping")
49    mut buffer: [8]u8 = zeroed
50    got: usize = try net.receive(state.network, connection, buffer)
51    fail io.io_failed when cmp.compare(buffer[0..<got], "pong") <> cmp.equal
52    mark(u8('d'))
53end call
54
55--  Module storage, so the stacks are no frame's: Cortex-M0's reset stack
56--  is 4 KiB, and its 12 KiB of RAM below that hold two stacks of 4 KiB.
57--  A 64-bit target's frames are deeper, and RV64's, which keep a home
58--  for every scalar, deepest: a task here takes more than 8 KiB there.
59fixed if compiler.word_size == 32 then
60    mut backing: [2 * 4096]u8 = zeroed
61else
62    mut backing: [2 * 12288]u8 = zeroed
63end if
64
65--  One exchange over a fresh network, the server's fibre started first
66--  or the client's; how many turns its calls took.
67exchange: (runs: any fibre.turns, server_first: bool)
68          -> (turns: usize) ! failure.reason =
69    mut space: fake.network_space = zeroed
70    mut b0: [16]u8 = zeroed
71    mut b1: [16]u8 = zeroed
72    mut b2: [16]u8 = zeroed
73    mut sockets: [3]fake.network_socket =
74        [fake.socket_over(b0), fake.socket_over(b1), fake.socket_over(b2)]
75    network := fake.network_over_turns(space, sockets, runs)
76    listener: io.file = try net.listen(network, net.loopback(net.ipv4, 0))
77    defer net.close_socket(network, listener) else none
78    at: net.address = try net.local_address(network, listener)
79    shared: party = (network: network, listener: listener, to: at)
80    mut tasks := try fibre.turns_over(runs, backing, 2)
81    defer fibre.join(tasks) else none
82    if server_first then
83        try fibre.admit(tasks, serve, shared)
84        try fibre.admit(tasks, call, shared)
85    else
86        try fibre.admit(tasks, call, shared)
87        try fibre.admit(tasks, serve, shared)
88    end if
89    try fibre.join(tasks)
90    turns = space.turns
91end exchange
92
93public main: () -> (code: i32) =
94    code = 1
95    mut state: stacks.round_space = zeroed
96    mut entries: [3]usize = zeroed
97    idler: stacks.spin = zeroed
98    round := stacks.round_over(state, entries, any(addr idler)) else (problem)
99        _ = problem
100        return
101    end
102    first: usize = exchange(any(addr round), true) else (problem)
103        _ = problem
104        return
105    end
106    code = 2
107    return when cmp.compare(trace[0..<marks], "card") <> cmp.equal
108      or first <> 2
109    code = 3
110    marks = 0
111    second: usize = exchange(any(addr round), false) else (problem)
112        _ = problem
113        return
114    end
115    code = 4
116    return when cmp.compare(trace[0..<marks], "card") <> cmp.equal
117      or second <> 1
118    code = 42
119end main