compiler/tests/fixtures/runtime/network-fake-turns-exchange/main.ldn
skip to the library navigation
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