hare

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

commit 20d9277ba522f8da0245689e742770cdb860c990
parent 72cbcd3a31b00414f9e5285e70c85149b6ff8925
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun,  7 Feb 2021 10:34:58 -0500

rt: convert syscall returns into useful hare values

Diffstat:
Mos/+linux/fdstream.ha | 15++++++---------
Mos/+linux/open.ha | 5++---
Mrt/+linux/errno.ha | 2+-
Mrt/+linux/segmalloc.ha | 20+++++++++++++++-----
Mrt/+linux/stat.ha | 2+-
Mrt/+linux/syscalls.ha | 108++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
Mrt/malloc.ha | 3+--
7 files changed, 108 insertions(+), 47 deletions(-)

diff --git a/os/+linux/fdstream.ha b/os/+linux/fdstream.ha @@ -57,8 +57,7 @@ export fn streamfd(s: *io::stream) (int | void) = { fn fd_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { let stream = s: *fd_stream; - let r = rt::read(stream.fd, buf: *[*]u8, len(buf)); - return match (rt::wrap_return(r)) { + return match (rt::read(stream.fd, buf: *[*]u8, len(buf))) { err: rt::errno => errno_to_io(err), n: size => switch (n) { 0z => io::EOF, @@ -69,8 +68,7 @@ fn fd_read(s: *io::stream, buf: []u8) (size | io::EOF | io::error) = { fn fd_write(s: *io::stream, buf: const []u8) (size | io::error) = { let stream = s: *fd_stream; - let r = rt::write(stream.fd, buf: *const [*]u8, len(buf)); - return match (rt::wrap_return(r)) { + return match (rt::write(stream.fd, buf: *const [*]u8, len(buf))) { err: rt::errno => errno_to_io(err), n: size => n, }; @@ -99,8 +97,8 @@ fn fd_copy(_to: *io::stream, _from: *io::stream) (size | io::error) = { let to = _to: *fd_stream, from = _from: *fd_stream; let sum = 0z; for (true) { - let r = rt::sendfile(to.fd, from.fd, null, SENDFILE_MAX); - let n = match(rt::wrap_return(r)) { + let n = match(rt::sendfile(to.fd, from.fd, + null, SENDFILE_MAX)) { err: rt::errno => switch (err) { rt::EINVAL => { if (sum == 0z) { @@ -126,9 +124,8 @@ fn fd_seek( whence: io::whence, ) (io::off | io::error) = { let stream = s: *fd_stream; - let r = rt::lseek(stream.fd, off: i64, whence: uint); - return match (rt::wrap_return(r: size)) { + return match (rt::lseek(stream.fd, off: i64, whence: uint)) { err: rt::errno => errno_to_io(err), - n: size => n: io::off, + n: i64 => n: io::off, }; }; diff --git a/os/+linux/open.ha b/os/+linux/open.ha @@ -48,10 +48,9 @@ export fn open( m |= flag[i]: int; }; - let r = rt::open(p: *[*]u8: *const char, m, 0u); - let fd: int = match (rt::wrap_return(r)) { + let fd: int = match (rt::open(p: *[*]u8: *const char, m, 0u)) { err: rt::errno => return errno_to_io(err), - n: size => n: int, + n: int => n, }; return fdopen(fd, name, mode); diff --git a/rt/+linux/errno.ha b/rt/+linux/errno.ha @@ -6,7 +6,7 @@ export fn wrap_errno(err: int) errno = err: errno; // Checks the return value from a Linux syscall and, if found to be in error, // returns the appropriate error. Otherwise, returns the original value. -export fn wrap_return(r: u64) (errno | size) = { +fn wrap_return(r: u64) (errno | u64) = { if (r > -4096u64) { return (-(r: i64)): int: errno; }; diff --git a/rt/+linux/segmalloc.ha b/rt/+linux/segmalloc.ha @@ -1,13 +1,23 @@ // Allocates a segment. fn segmalloc(n: size) nullable *void = { - let p: *void = mmap(null, n, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0z); - return if (p: uintptr: int == -ENOMEM) null else p; + return match(mmap(null, n, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0z)) { + err: errno => { + assert(err == ENOMEM: errno); + null; + }, + p: *void => p, + }; }; // Frees a segment allocated with segmalloc. -fn segfree(p: *void, s: size) int = munmap(p, s); +fn segfree(p: *void, s: size) void = { + match (munmap(p, s)) { + err: errno => abort("munmap failed"), + void => void, + }; +}; // Marks a segment as writable and drops the execute bit. fn segwrite(seg: *void, n: size) void = mprotect(seg, n, PROT_READ | PROT_WRITE); diff --git a/rt/+linux/stat.ha b/rt/+linux/stat.ha @@ -14,7 +14,7 @@ fn fstatat_statx( SYS_statx, dirfd: u64, path: uintptr: u64, flags: u64, mask: u64, statbuf: uintptr: u64))) { err: errno => err, - size => void, + u64 => void, }; export fn fstatat( diff --git a/rt/+linux/syscalls.ha b/rt/+linux/syscalls.ha @@ -6,28 +6,59 @@ fn syscall4(u64, u64, u64, u64, u64) u64; fn syscall5(u64, u64, u64, u64, u64, u64) u64; fn syscall6(u64, u64, u64, u64, u64, u64, u64) u64; -export fn read(fd: int, buf: *void, count: size) size = - syscall3(SYS_read, fd: u64, buf: uintptr: u64, count: u64): size; +export fn read(fd: int, buf: *void, count: size) (size | errno) = { + return match (wrap_return(syscall3(SYS_read, + fd: u64, buf: uintptr: u64, count: u64))) { + err: errno => err, + n: u64 => n: size, + }; +}; -export fn write(fd: int, buf: *const void, count: size) size = - syscall3(SYS_write, fd: u64, buf: uintptr: u64, count: u64): size; +export fn write(fd: int, buf: *const void, count: size) (size | errno) = { + return match (wrap_return(syscall3(SYS_write, + fd: u64, buf: uintptr: u64, count: u64))) { + err: errno => err, + n: u64 => n: size, + }; +}; -export fn open(path: *const char, flags: int, mode: uint) size = { - return syscall4(SYS_openat, AT_FDCWD: u64, - path: uintptr: u64, flags: u64, mode: u64): size; +export fn open(path: *const char, flags: int, mode: uint) (int | errno) = { + return match (wrap_return(syscall4(SYS_openat, AT_FDCWD: u64, + path: uintptr: u64, flags: u64, mode: u64))) { + err: errno => err, + n: u64 => n: int, + }; }; -export fn close(fd: int) int = syscall1(SYS_close, fd: u64): int; +export fn close(fd: int) (void | errno) = { + return match (wrap_return(syscall1(SYS_close, fd: u64))) { + err: errno => err, + u64 => void, + }; +}; export fn getpid() int = syscall0(SYS_getpid): int; -export fn sendfile(out: int, in: int, offs: nullable *size, count: size) size = - syscall4(SYS_sendfile, out: u64, in: u64, offs: uintptr: u64, count: u64): size; +export fn sendfile( + out: int, + in: int, + offs: nullable *size, + count: size, +) (size | errno) = match (wrap_return(syscall4(SYS_sendfile, + out: u64, in: u64, offs: uintptr: u64, count: u64))) { + n: u64 => n: size, + err: errno => err, +}; + export @noreturn fn exit(status: int) void = syscall1(SYS_exit, status: u64); -export fn kill(pid: int, signal: int) int = - syscall2(SYS_kill, pid: u64, signal: u64): int; +export fn kill(pid: int, signal: int) (void | errno) = { + return match (wrap_return(syscall2(SYS_kill, pid: u64, signal: u64))) { + err: errno => err, + u64 => void, + }; +}; export fn mmap( addr: nullable *void, @@ -36,21 +67,46 @@ export fn mmap( flags: uint, fd: int, offs: size -) *void = { - let r: u64 = syscall6(SYS_mmap, addr: uintptr: u64, - length: u64, prot: u64, flags: u64, fd: u64, offs: u64): u64; - // TODO: Type promotion - return if (r: int == -EPERM && addr: uintptr == null: uintptr - && (flags & MAP_ANON) > 0u && (flags & MAP_FIXED) == 0u) { - (-ENOMEM): uintptr: *void; // Fix up incorrect EPERM from kernel - } else r: uintptr: *void; +) (*void | errno) = { + let r = syscall6(SYS_mmap, addr: uintptr: u64, + length: u64, prot: u64, flags: u64, fd: u64, offs: u64); + match (wrap_return(r)) { + err: errno => { + // XXX: Type promotion would simplify this + return if (r: int == -EPERM + && addr: uintptr == null: uintptr + && (flags & MAP_ANON) > 0u + && (flags & MAP_FIXED) == 0u) { + // Fix up incorrect EPERM from kernel: + wrap_errno(ENOMEM); + } else err; + }, + n: u64 => n: uintptr: *void, + }; }; -export fn munmap(addr: *void, length: size) int = - syscall2(SYS_munmap, addr: uintptr: u64, length: u64): int; +export fn munmap(addr: *void, length: size) (void | errno) = { + return match (wrap_return(syscall2(SYS_munmap, + addr: uintptr: u64, length: u64))) { + err: errno => err, + u64 => void, + }; +}; + -export fn mprotect(addr: *void, length: size, prot: uint) int = - syscall3(SYS_mprotect, addr: uintptr: u64, length: u64, prot: u64): int; +export fn mprotect(addr: *void, length: size, prot: uint) (void | errno) = { + return match (wrap_return(syscall3(SYS_mprotect, + addr: uintptr: u64, length: u64, prot: u64))) { + err: errno => err, + u64 => void, + }; +}; + -export fn lseek(fd: int, off: i64, whence: uint) i64 = - syscall3(SYS_lseek, fd: u64, off: u64, whence: u64): i64; +export fn lseek(fd: int, off: i64, whence: uint) (i64 | errno) = { + return match (wrap_return(syscall3(SYS_lseek, + fd: u64, off: u64, whence: u64))) { + err: errno => err, + n: u64 => n: i64, + }; +}; diff --git a/rt/malloc.ha b/rt/malloc.ha @@ -122,8 +122,7 @@ export @symbol("rt.free") fn free_(_p: nullable *void) void = { fn free_large(_p: *void, s: size) void = { let p = (_p: uintptr - (WASTE: uintptr + WORD: uintptr)): *void; - let r = segfree(p, s + WASTE + WORD); - assert(r == 0, "free: munmap failed"); + segfree(p, s + WASTE + WORD); }; fn free_small(p: *void, s: size) void = {