1-- Linux's own event interfaces, on x86-64, arm64 and RV64: epoll, which
2-- waits until any of many descriptors is ready, and signalfd, which reads
3-- signals as records from a descriptor epoll can watch, with
4-- `rt_sigprocmask` to block the signals a signalfd reads so that none is
5-- delivered first. They are raw, as the rest of this module is: a
6-- failure is minus the errno. The loop's own sleep is the wait's time
7-- limit and nothing else wakes it, so there is no eventfd or timerfd here
8-- (D480). Declared on Linux only, as the module is.
9
10fixed if compiler.os == linux then
11 --- `epoll_create1` flag: the new epoll descriptor is closed when the
12 --- process executes a program, `EPOLL_CLOEXEC`.
13 public epoll_cloexec: i32 = 524288
14
15 --- `epoll_ctl` operation: watch a descriptor not yet watched.
16 public epoll_ctl_add: i32 = 1
17 --- `epoll_ctl` operation: stop watching a descriptor.
18 public epoll_ctl_del: i32 = 2
19 --- `epoll_ctl` operation: change what a watched descriptor is watched
20 --- for.
21 public epoll_ctl_mod: i32 = 3
22
23 --- epoll event: data to read, or the end of a file, `EPOLLIN`.
24 public epollin: u32 = 1
25 --- epoll event: urgent data to read, `EPOLLPRI`.
26 public epollpri: u32 = 2
27 --- epoll event: room to write, `EPOLLOUT`.
28 public epollout: u32 = 4
29 --- epoll event, always reported: an error on the descriptor,
30 --- `EPOLLERR`.
31 public epollerr: u32 = 8
32 --- epoll event, always reported: the peer has gone, `EPOLLHUP`.
33 public epollhup: u32 = 16
34 --- epoll event: a stream's peer has shut its sending side,
35 --- `EPOLLRDHUP`.
36 public epollrdhup: u32 = 8192
37 --- epoll flag: report the descriptor once and then not again until
38 --- `epoll_ctl_mod` asks again, `EPOLLONESHOT`.
39 public epolloneshot: u32 = 1073741824
40 --- epoll flag: report a change of readiness rather than readiness,
41 --- `EPOLLET`.
42 public epollet: u32 = 2147483648
43
44 fixed if compiler.arch == x86_64 then
45 --- The kernel's `struct epoll_event`: the events asked about or
46 --- reported, and a word the kernel hands back unread with each
47 --- report. x86-64 alone packs it, to twelve bytes, so that its
48 --- 32-bit compatibility layer reads the same record.
49 public epoll_record: type = layout(c, packed) struct
50 events: u32
51 data: u64
52 end epoll_record
53 else
54 --- The kernel's `struct epoll_event`: the events asked about or
55 --- reported, and a word the kernel hands back unread with each
56 --- report. Sixteen bytes on arm64 and RV64, the word aligned.
57 public epoll_record: type = struct
58 events: u32
59 data: u64
60 end epoll_record
61 end if
62
63 --- Make an epoll descriptor, with `flags`, `epoll_cloexec` among them:
64 --- the new descriptor, or minus the errno.
65 public epoll_create1:
66 (flags: i32) -> (result: i32) =
67 result = i32(system_call(epoll_create1_number, i64(flags), 0, 0, 0,
68 0, 0))
69 end epoll_create1
70
71 --- Watch `descriptor` from `epoll` for what `event` asks, change what it
72 --- is watched for, or stop watching it, as `operation` says: zero, or
73 --- minus the errno, EEXIST when it is added twice and ENOENT when one
74 --- not watched is changed or removed. `epoll_ctl_del` does not read
75 --- `event`. A descriptor is watched until it is removed or every
76 --- descriptor for its open file is closed, so one closed while a
77 --- duplicate stays open is still reported.
78 public epoll_ctl:
79 (epoll: i32, operation: i32, descriptor: i32, event: ptr epoll_record)
80 -> (result: i32) =
81 result = i32(system_call(epoll_ctl_number, i64(epoll),
82 i64(operation), i64(descriptor),
83 i64(usize(event)), 0, 0))
84 end epoll_ctl
85
86 --- What `epoll_pwait` and `signalfd4` take for no signal mask: C's
87 --- null pointer.
88 public no_mask: atom
89 --- A signal mask a call reads, a set of signals, the kernel's eight
90 --- bytes with signal N at bit N - 1, or `no_mask`.
91 public mask_given: type = no_mask | ptr u64
92 --- Where `rt_sigprocmask` puts the mask it replaces, or `no_mask`.
93 public mask_kept: type = no_mask | ptr mut u64
94
95 -- The address an optional mask is, zero for none.
96 given_mask: (given: mask_given) -> (address: i64) =
97 address = match given
98 no_mask: i64(0)
99 ptr (mask): i64(usize(mask))
100 end match
101 end given_mask
102
103 --- Wait until one of the descriptors `epoll` watches is ready or
104 --- `milliseconds` pass, waiting indefinitely when it is negative and not
105 --- at all when it is zero, with the signal mask `mask` in place while it
106 --- waits when one is given, and fill at most `count` records at
107 --- `events`, each with its events and the word it was watched with: how
108 --- many it filled, zero when the time passed first, or minus the errno,
109 --- EINTR when a signal came first. arm64 and RV64 have no
110 --- `epoll_wait`; this is every architecture's.
111 public epoll_pwait:
112 (epoll: i32, events: ptr mut epoll_record, count: i32,
113 milliseconds: i32, mask: mask_given) -> (result: i32) =
114 result = i32(system_call(epoll_pwait_number, i64(epoll),
115 i64(usize(events)), i64(count),
116 i64(milliseconds), given_mask(mask), 8))
117 end epoll_pwait
118
119 --- Signal: the terminal hung up, or a daemon is asked to reload,
120 --- SIGHUP. Linux numbers the signals one way on all three
121 --- architectures.
122 public sighup: i32 = 1
123 --- Signal: interrupted from the terminal, SIGINT.
124 public sigint: i32 = 2
125 --- Signal: the first one a program defines, SIGUSR1.
126 public sigusr1: i32 = 10
127 --- Signal: the second one a program defines, SIGUSR2.
128 public sigusr2: i32 = 12
129 --- Signal: asked to end, SIGTERM.
130 public sigterm: i32 = 15
131
132 --- The bit of `signal` in the kernel's signal mask.
133 public signal_bit:
134 (signal: i32) -> (bit: u64) =
135 bit = 0
136 return when signal < 1 or signal > 64
137 bit = u64(1) << u64(signal - 1)
138 end signal_bit
139
140 --- `rt_sigprocmask` operation: block the signals given beside those
141 --- blocked already, `SIG_BLOCK`.
142 public sig_block: i32 = 0
143 --- `rt_sigprocmask` operation: unblock the signals given,
144 --- `SIG_UNBLOCK`.
145 public sig_unblock: i32 = 1
146 --- `rt_sigprocmask` operation: block exactly the signals given,
147 --- `SIG_SETMASK`.
148 public sig_setmask: i32 = 2
149
150 --- Change the calling thread's mask of blocked signals by `how` with
151 --- `mask` when it is given, and put the mask it had in `previous` when
152 --- that is given: zero, or minus the errno. A blocked signal stays
153 --- pending until it is unblocked or a signalfd reads it; the mask is
154 --- the thread's, a child copies it and an executed program keeps it.
155 public rt_sigprocmask:
156 (how: i32, mask: mask_given, previous: mask_kept) -> (result: i32) =
157 keeping: i64 = match previous
158 no_mask: i64(0)
159 ptr (kept): i64(usize(kept))
160 end match
161 result = i32(system_call(rt_sigprocmask_number, i64(how),
162 given_mask(mask), keeping, 8, 0, 0))
163 end rt_sigprocmask
164
165 --- `signalfd4` flag: the new descriptor is closed when the process
166 --- executes a program, `SFD_CLOEXEC`.
167 public sfd_cloexec: i32 = 524288
168 --- `signalfd4` flag: a read with no signal pending fails with EAGAIN
169 --- rather than waiting, `SFD_NONBLOCK`, which is `o_nonblock`.
170 public sfd_nonblock: i32 = 2048
171
172 --- What a read of a signalfd gives for each signal, the kernel's
173 --- `struct signalfd_siginfo`: 128 bytes, one layout on every
174 --- architecture. `signal` is its number; `process` and `user` are the
175 --- sender's for a signal another process sent.
176 public signalfd_record: type = struct
177 signal: u32
178 error: i32
179 code: i32
180 process: u32
181 user: u32
182 descriptor: i32
183 timer: u32
184 band: u32
185 overrun: u32
186 trap: u32
187 status: i32
188 integer: i32
189 pointer: u64
190 user_time: u64
191 system_time: u64
192 address: u64
193 address_low_bit: u16
194 padding: u16
195 call: i32
196 call_address: u64
197 architecture: u32
198 reserved: [28]u8
199 end signalfd_record
200
201 --- Make a descriptor that reads the signals in `mask` as
202 --- `signalfd_record`s, or with `descriptor` one made already change
203 --- which it reads, with `flags`, `sfd_cloexec` and `sfd_nonblock` among
204 --- them; -1 asks for a new one: the descriptor, or minus the errno.
205 --- It reads only signals that are pending, so the signals must be
206 --- blocked with `rt_sigprocmask` first, or a signal is delivered as its
207 --- disposition says before it can be read.
208 public signalfd4:
209 (descriptor: i32, mask: ptr u64, flags: i32) -> (result: i32) =
210 result = i32(system_call(signalfd4_number, i64(descriptor),
211 i64(usize(mask)), 8, i64(flags), 0, 0))
212 end signalfd4
213
214 --- `fcntl` command: read a descriptor's open-file flags, `o_nonblock`
215 --- among them, `F_GETFL`.
216 public f_getfl: i32 = 3
217 --- `fcntl` command: set a descriptor's open-file flags, `F_SETFL`.
218 public f_setfl: i32 = 4
219 --- `openat`, `pipe2`, `socket`, `accept4` and `fcntl` flag: a call that
220 --- would wait fails with EAGAIN instead, `O_NONBLOCK`. The same on
221 --- x86-64, arm64 and RV64.
222 public o_nonblock: i32 = 2048
223 --- `socket` and `accept4` flag: the new socket is non-blocking, set
224 --- with it, `SOCK_NONBLOCK`.
225 public sock_nonblock: i32 = 2048
226end if