Landin library reference discuss source

platform/linux/events.ldn

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