commit 078fc33bf766986caa93eb0fbd06b2843267ef3d
parent cc66165dd42e0e89cd641b9fb932b41060580ea7
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 23 Jul 2021 16:29:44 +0200
unix::poll: new module
This also updates net::dns to use unix::poll instead of rt::ppoll
directly.
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
5 files changed, 92 insertions(+), 17 deletions(-)
diff --git a/encoding/base64/base64.ha b/encoding/base64/base64.ha
@@ -33,8 +33,8 @@ export def PADDING: u8 = '=': u32: u8;
// Indicates that invalid input was found while decoding, either in the form of
// characters outside of the base 64 alphabet, insufficient padding, or trailing
-// characters. Contains the index of the first invalid character which may be
-// outside of the bounds of the provided input if more input was expected.
+// characters. Contains the index of the first invalid character, which may be
+// outside of the bounds of a truncated input.
export type invalid = !size;
// Encodes a byte slice using a base 64 encoding alphabet, with padding, and
diff --git a/net/dns/query.ha b/net/dns/query.ha
@@ -1,8 +1,8 @@
use errors;
use net::ip;
use net::udp;
-use rt;
use time;
+use unix::poll;
use unix::resolvconf;
// TODO: Let user customize this?
@@ -13,9 +13,7 @@ def timeout: time::duration = 3 * time::SECOND;
//
// If no DNS servers are provided, the system default servers (if any) are used.
export fn query(query: *message, servers: ip::addr...) (*message | error) = {
- // TODO:
- // - Swap rt::poll for unix::poll
- // - Use TCP for messages >512 bytes
+ // TODO: Use TCP for messages >512 bytes
if (len(servers) == 0) {
servers = resolvconf::load();
};
@@ -31,15 +29,15 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
defer udp::close(socket4);
const socket6 = udp::listen(ip::ANY_V6, 0)?;
defer udp::close(socket6);
- const pollfd: [_]rt::pollfd = [
- rt::pollfd {
+ const pollfd: [_]poll::pollfd = [
+ poll::pollfd {
fd = udp::sockfd(socket4),
- events = rt::POLLIN,
+ events = poll::event::POLLIN,
...
},
- rt::pollfd {
+ poll::pollfd {
fd = udp::sockfd(socket6),
- events = rt::POLLIN,
+ events = poll::event::POLLIN,
...
},
];
@@ -61,19 +59,16 @@ export fn query(query: *message, servers: ip::addr...) (*message | error) = {
let header = header { ... };
let recvbuf: [512]u8 = [0...];
for (true) {
- let ts = rt::timespec { ... };
- time::duration_to_timespec(timeout, &ts);
- let nevent = rt::ppoll(&pollfd: *[*]rt::pollfd,
- len(pollfd), &ts, null)!;
+ let nevent = poll::poll(pollfd, timeout)!;
if (nevent == 0) {
return errors::timeout;
};
let src: ip::addr = ip::ANY_V4;
- if (pollfd[0].revents & rt::POLLIN == rt::POLLIN) {
+ if (pollfd[0].revents & poll::event::POLLIN != 0) {
z = udp::recvfrom(socket4, recvbuf, &src, null)?;
};
- if (pollfd[1].revents & rt::POLLIN == rt::POLLIN) {
+ if (pollfd[1].revents & poll::event::POLLIN != 0) {
z = udp::recvfrom(socket6, recvbuf, &src, null)?;
};
diff --git a/scripts/gen-stdlib b/scripts/gen-stdlib
@@ -798,6 +798,12 @@ unix_passwd() {
gen_ssa unix::passwd bufio io os strconv strings
}
+unix_poll() {
+ gen_srcs unix::poll \
+ '$(PLATFORM)'.ha
+ gen_ssa unix::poll rt errors time
+}
+
unix_resolvconf() {
gen_srcs unix::resolvconf \
load.ha
@@ -887,6 +893,7 @@ unicode
unix
unix::hosts
unix::passwd
+unix::poll
unix::resolvconf
unix::tty
uuid"
diff --git a/stdlib.mk b/stdlib.mk
@@ -341,6 +341,10 @@ hare_stdlib_deps+=$(stdlib_unix_hosts)
stdlib_unix_passwd=$(HARECACHE)/unix/passwd/unix_passwd.o
hare_stdlib_deps+=$(stdlib_unix_passwd)
+# gen_lib unix::poll
+stdlib_unix_poll=$(HARECACHE)/unix/poll/unix_poll.o
+hare_stdlib_deps+=$(stdlib_unix_poll)
+
# gen_lib unix::resolvconf
stdlib_unix_resolvconf=$(HARECACHE)/unix/resolvconf/unix_resolvconf.o
hare_stdlib_deps+=$(stdlib_unix_resolvconf)
@@ -1147,6 +1151,16 @@ $(HARECACHE)/unix/passwd/unix_passwd.ssa: $(stdlib_unix_passwd_srcs) $(stdlib_rt
@HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::passwd \
-t$(HARECACHE)/unix/passwd/unix_passwd.td $(stdlib_unix_passwd_srcs)
+# unix::poll
+stdlib_unix_poll_srcs= \
+ $(STDLIB)/unix/poll/$(PLATFORM).ha
+
+$(HARECACHE)/unix/poll/unix_poll.ssa: $(stdlib_unix_poll_srcs) $(stdlib_rt) $(stdlib_rt) $(stdlib_errors) $(stdlib_time)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(HARECACHE)/unix/poll
+ @HARECACHE=$(HARECACHE) $(HAREC) $(HAREFLAGS) -o $@ -Nunix::poll \
+ -t$(HARECACHE)/unix/poll/unix_poll.td $(stdlib_unix_poll_srcs)
+
# unix::resolvconf
stdlib_unix_resolvconf_srcs= \
$(STDLIB)/unix/resolvconf/load.ha
@@ -1524,6 +1538,10 @@ hare_testlib_deps+=$(testlib_unix_hosts)
testlib_unix_passwd=$(TESTCACHE)/unix/passwd/unix_passwd.o
hare_testlib_deps+=$(testlib_unix_passwd)
+# gen_lib unix::poll
+testlib_unix_poll=$(TESTCACHE)/unix/poll/unix_poll.o
+hare_testlib_deps+=$(testlib_unix_poll)
+
# gen_lib unix::resolvconf
testlib_unix_resolvconf=$(TESTCACHE)/unix/resolvconf/unix_resolvconf.o
hare_testlib_deps+=$(testlib_unix_resolvconf)
@@ -2354,6 +2372,16 @@ $(TESTCACHE)/unix/passwd/unix_passwd.ssa: $(testlib_unix_passwd_srcs) $(testlib_
@HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::passwd \
-t$(TESTCACHE)/unix/passwd/unix_passwd.td $(testlib_unix_passwd_srcs)
+# unix::poll
+testlib_unix_poll_srcs= \
+ $(STDLIB)/unix/poll/$(PLATFORM).ha
+
+$(TESTCACHE)/unix/poll/unix_poll.ssa: $(testlib_unix_poll_srcs) $(testlib_rt) $(testlib_rt) $(testlib_errors) $(testlib_time)
+ @printf 'HAREC \t$@\n'
+ @mkdir -p $(TESTCACHE)/unix/poll
+ @HARECACHE=$(TESTCACHE) $(HAREC) $(TESTHAREFLAGS) -o $@ -Nunix::poll \
+ -t$(TESTCACHE)/unix/poll/unix_poll.td $(testlib_unix_poll_srcs)
+
# unix::resolvconf
testlib_unix_resolvconf_srcs= \
$(STDLIB)/unix/resolvconf/load.ha
diff --git a/unix/poll/+linux.ha b/unix/poll/+linux.ha
@@ -0,0 +1,45 @@
+use errors;
+use time;
+use rt;
+
+// Events bitfield for the events and revents field of [[pollfd]].
+export type event = enum i16 {
+ POLLIN = 1,
+ POLLPRI = 2,
+ POLLOUT = 4,
+ POLLERR = 8,
+ POLLHUP = 16,
+};
+
+// A single file descriptor to be polled.
+export type pollfd = struct {
+ // XXX: TODO: Update me to io::file?
+ fd: int,
+ events: event,
+ revents: event,
+};
+
+// Pass this [[time::duration]] to [[poll]] to cause it wait indefinitely for
+// the next event.
+export def INDEF: time::duration = -1;
+
+// Pass this [[time::duration]] to [[poll]] to cause it to return immediately if
+// no events are available.
+export def NONBLOCK: time::duration = 0;
+
+// Polls for the desired events on a slice of [[pollfds]], blocking until an
+// event is available, or the timeout expires. Set the timeout to [[INDEF]] to
+// block forever, or [[NONBLOCK]] to return immediately if no events are
+// available. Returns the number of [[pollfd]] items which have events, i.e.
+// those which have revents set to a nonzero value.
+export fn poll(
+ fds: []pollfd,
+ timeout: time::duration,
+) (uint | errors::error) = {
+ let ts = rt::timespec { ... };
+ time::duration_to_timespec(timeout, &ts);
+ return match (rt::ppoll(fds: *[*]pollfd, len(fds), &ts, null)) {
+ err: rt::errno => errors::errno(err),
+ n: int => n: uint,
+ };
+};