hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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:
Mencoding/base64/base64.ha | 4++--
Mnet/dns/query.ha | 25++++++++++---------------
Mscripts/gen-stdlib | 7+++++++
Mstdlib.mk | 28++++++++++++++++++++++++++++
Aunix/poll/+linux.ha | 45+++++++++++++++++++++++++++++++++++++++++++++
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, + }; +};