Closed
Description
Currently, we have these OS-specific APIs:
- std.os.linux
- std.os.windows
- std.os.darwin
- std.os.freebsd
- std.os.netbsd
- std.os.wasi
std.os.posix is defined like this:
pub const posix = switch (builtin.os) {
Os.linux => linux,
Os.macosx, Os.ios => darwin,
Os.freebsd => freebsd,
Os.netbsd => netbsd,
Os.wasi => wasi,
else => @compileError("Unsupported OS"),
};
So what we have is an identifier posix
that is mapped directly to the OS-specific API for all platforms except Windows. This is problematic for several reasons:
- Each OS-specific API has a different set of functions available.
- Some functions have different number of or incompatible parameters.
- It's quite possible to implement a POSIX API layer on top of windows, at least for some things.
- We have this
std.os.posixFoo
pattern, which is a code smell, because all the functions are all prefixed withposix
but cannot be in theposix
namespace. - There is a need for "glue code" to work around kernel API footguns. For example when the number of
iov_len
is greater than some kernel-defined limit, it has to be broken into multiple syscalls. Or when the number of bytes to thewrite
syscall is greater than some number, it has to be broken into multiple syscalls.
This led to 4a8c992 in which, for example, std.os.linux.fork
surprisingly does not cause a fork syscall. Further, with the WASI ABI, it's clear that there is a separate "core" API layer as well as a "POSIX" API layer.
I propose to make the following changes:
- Make the OS-specific files do exactly what they say. E.g. if you call
std.os.linux.fork
, that is going to do the fork syscall when you observe the program with strace, guaranteed. - Instead of std.os.posix mapping directly to OS-specific files, it will provide a "zig flavored POSIX" API on top of the native OS API. This is where kernel limitations will be worked around;
fork
might callclone
on Linux, etc. - Functions matching the pattern
std.os.posixFoo
will be moved tostd.os.posix.foo
. In Zig-flavored POSIX, errno is not exposed; instead actual zig error unions and error sets are used. When not linking libc on Linux there will never be an errno variable, because the syscall return code contains the error code in it. However for OS-specific APIs, where that OS requires the use of libc, errno may be exposed, for example asstd.os.darwin.errno()
. - There will even be a zig flavored POSIX API for Windows. Some functions may cause a compile error if the abstraction does not hold up, but for some things, it will work fine.