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:
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 = {