Landin library reference discuss source

platform/posix/poll.ldn

1--  Waiting for descriptors to be ready: POSIX's `poll`, its records and
2--  the events it reports.
3
4import platform/libc
5import platform/linux
6
7events_value: type = distinct u16
8
9--- Poll events, POSIX's `poll` bits as a set: a value combines with `|`,
10--- `&` and `~` and compares with `==` and `<>`.  `poll_input`,
11--- `poll_output` and `poll_urgent` are what an entry can ask about;
12--- `poll_error`, `poll_hung_up` and `poll_invalid` are only ever
13--- reported.  The bits are the same on Linux,
14--- Darwin and FreeBSD.
15public poll_events: type = events_value
16
17--- No event.
18public poll_no_events: poll_events = events_value(0)
19
20--- Data to read, or the end of a file.
21public poll_input: poll_events = events_value(1)
22
23--- Out-of-band data to read.
24public poll_urgent: poll_events = events_value(2)
25
26--- Room to write.
27public poll_output: poll_events = events_value(4)
28
29--- An error on the file.
30public poll_error: poll_events = events_value(8)
31
32--- The peer has gone.
33public poll_hung_up: poll_events = events_value(16)
34
35--- A descriptor that is not open.
36public poll_invalid: poll_events = events_value(32)
37
38--  C's `struct pollfd`, the same on all three systems, so a slice of
39--  entries is what the system reads and fills: `short` fields, whose bits
40--  these are.
41poll_record: type = struct
42    descriptor: descriptor
43    events: poll_events
44    returned: poll_events
45end poll_record
46
47--- One descriptor for `poll` to watch and the events asked about, made by
48--- `watch`, and after the call what happened, which `happened` reads.
49public poll_entry: type = poll_record
50
51--- An entry watching `watched` for the events `wanted` asks about; its
52--- `poll_error`, `poll_hung_up` and `poll_invalid` are reported whether
53--- asked or not.
54public link(symbol: "_landin_posix_watch") watch:
55    (watched: descriptor, wanted: poll_events)
56    -> (entry: poll_entry) =
57    asked: poll_events = poll_input | poll_urgent | poll_output
58    entry = (descriptor: watched, events: wanted & asked,
59             returned: poll_no_events)
60end watch
61
62--- What happened to an entry's descriptor in the last `poll`; nothing,
63--- before one.
64public link(symbol: "_landin_posix_happened") happened:
65    (entry: poll_entry) -> (events: poll_events) =
66    events = entry.returned
67end happened
68
69--- Wait until an event happens to one of `entries`' descriptors, or
70--- `milliseconds` pass, waiting indefinitely when it is negative and not
71--- at all when it is zero, POSIX's `poll`: how many entries had an event,
72--- each of which `happened` reads, zero when the time passed first, or
73--- the errno, `eintr` when a signal came first.
74public link(symbol: "_landin_posix_poll") poll:
75    (entries: []mut poll_entry, milliseconds: i32)
76    -> (ready: usize) ! errno =
77    ready = try system_poll(entries, milliseconds)
78end poll
79
80--  The system's own calls beneath the facility above: Linux's system
81--  calls through platform/linux, and the C library through
82--  platform/libc on Darwin and FreeBSD, whose system interface it is.
83
84fixed if compiler.os == linux then
85    --  arm64 and RV64 have no `poll` call, so every architecture makes
86    --  `ppoll`, with the milliseconds as its time limit.
87    system_poll: (entries: []mut poll_entry, milliseconds: i32)
88                 -> (ready: usize) ! errno =
89        mut spare: linux.poll_record = zeroed
90        records: ptr mut linux.poll_record =
91            if lenof entries > 0 then ptr(usize(addr entries[0]))
92            else addr spare end if
93        mut limit: linux.timespec = zeroed
94        limit.seconds = i64(milliseconds / 1000)
95        limit.nanoseconds = i64(milliseconds % 1000) * 1000000
96        bound: linux.poll_limit = if milliseconds < 0 then linux.no_limit
97                                  else addr limit end if
98        result: i32 = linux.ppoll(records, lenof entries, bound)
99        fail errno_of(-result) when result < 0
100        ready = usize(result)
101    end system_poll
102elsif compiler.os == darwin or compiler.os == freebsd then
103    system_poll: (entries: []mut poll_entry, milliseconds: i32)
104                 -> (ready: usize) ! errno =
105        mut spare: libc.poll_record = zeroed
106        records: ptr mut libc.poll_record =
107            if lenof entries > 0 then ptr(usize(addr entries[0]))
108            else addr spare end if
109        result: i32 = libc.poll(records, libc.poll_count(lenof entries),
110                                milliseconds)
111        fail failure() when result < 0
112        ready = usize(result)
113    end system_poll
114end if