2
0
Эх сурвалжийг харах

Implement new sys/unix package

flysand7 1 жил өмнө
parent
commit
4d65b1ab9c

+ 21 - 22
core/crypto/rand_linux.odin

@@ -1,8 +1,8 @@
 package crypto
 
 import "core:fmt"
-import "core:os"
-import "core:sys/unix"
+
+import "core:sys/linux"
 
 _MAX_PER_CALL_BYTES :: 33554431 // 2^25 - 1
 
@@ -12,26 +12,25 @@ _rand_bytes :: proc (dst: []byte) {
 
 	for l > 0 {
 		to_read := min(l, _MAX_PER_CALL_BYTES)
-		ret := unix.sys_getrandom(raw_data(dst), uint(to_read), 0)
-		if ret < 0 {
-			switch os.Errno(-ret) {
-			case os.EINTR:
-				// Call interupted by a signal handler, just retry the
-				// request.
-				continue
-			case os.ENOSYS:
-				// The kernel is apparently prehistoric (< 3.17 circa 2014)
-				// and does not support getrandom.
-				panic("crypto: getrandom not available in kernel")
-			case:
-				// All other failures are things that should NEVER happen
-				// unless the kernel interface changes (ie: the Linux
-				// developers break userland).
-				panic(fmt.tprintf("crypto: getrandom failed: %d", ret))
-			}
+		n_read, errno := linux.getrandom(dst[:to_read], {})
+		#partial switch errno {
+		case .NONE:
+			// Do nothing
+		case .EINTR:
+			// Call interupted by a signal handler, just retry the
+			// request.
+			continue
+		case .ENOSYS:
+			// The kernel is apparently prehistoric (< 3.17 circa 2014)
+			// and does not support getrandom.
+			panic("crypto: getrandom not available in kernel")
+		case:
+			// All other failures are things that should NEVER happen
+			// unless the kernel interface changes (ie: the Linux
+			// developers break userland).
+			panic(fmt.tprintf("crypto: getrandom failed: %v", errno))
 		}
-
-		l -= ret
-		dst = dst[ret:]
+		l -= n_read
+		dst = dst[n_read:]
 	}
 }

+ 18 - 17
core/math/rand/system_linux.odin

@@ -1,27 +1,28 @@
 package rand
 
-import "core:sys/unix"
+import "core:sys/linux"
 
 @(require_results)
 _system_random :: proc() -> u64 {
 	for {
 		value: u64
-		ret := unix.sys_getrandom(([^]u8)(&value), size_of(value), 0)
-		if ret < 0 {
-			switch ret {
-			case -4: // EINTR
-				// Call interupted by a signal handler, just retry the request.
-				continue
-			case -38: // ENOSYS
-				// The kernel is apparently prehistoric (< 3.17 circa 2014)
-				// and does not support getrandom.
-				panic("getrandom not available in kernel")
-			case:
-				// All other failures are things that should NEVER happen
-				// unless the kernel interface changes (ie: the Linux
-				// developers break userland).
-				panic("getrandom failed")
-			}
+		value_buf := (cast([^]u8)&value)[:size_of(u64)]
+		_, errno := linux.getrandom(value_buf, {})
+		#partial switch errno {
+		case .NONE:
+			// Do nothing
+		case .EINTR: 
+			// Call interupted by a signal handler, just retry the request.
+			continue
+		case .ENOSYS: 
+			// The kernel is apparently prehistoric (< 3.17 circa 2014)
+			// and does not support getrandom.
+			panic("getrandom not available in kernel")
+		case:
+			// All other failures are things that should NEVER happen
+			// unless the kernel interface changes (ie: the Linux
+			// developers break userland).
+			panic("getrandom failed")
 		}
 		return value
 	}

+ 23 - 74
core/mem/virtual/virtual_linux.odin

@@ -2,100 +2,49 @@
 //+private
 package mem_virtual
 
-import "core:c"
-import "core:intrinsics"
-import "core:sys/unix"
-
-PROT_NONE  :: 0x0
-PROT_READ  :: 0x1
-PROT_WRITE :: 0x2
-PROT_EXEC  :: 0x4
-PROT_GROWSDOWN :: 0x01000000
-PROT_GROWSUP :: 0x02000000
-
-MAP_FIXED     :: 0x1
-MAP_PRIVATE   :: 0x2
-MAP_SHARED    :: 0x4
-MAP_ANONYMOUS :: 0x20
-
-MADV_NORMAL      :: 0
-MADV_RANDOM      :: 1
-MADV_SEQUENTIAL  :: 2
-MADV_WILLNEED    :: 3
-MADV_DONTNEED    :: 4
-MADV_FREE        :: 8
-MADV_REMOVE      :: 9
-MADV_DONTFORK    :: 10
-MADV_DOFORK      :: 11
-MADV_MERGEABLE   :: 12
-MADV_UNMERGEABLE :: 13
-MADV_HUGEPAGE    :: 14
-MADV_NOHUGEPAGE  :: 15
-MADV_DONTDUMP    :: 16
-MADV_DODUMP      :: 17
-MADV_WIPEONFORK  :: 18
-MADV_KEEPONFORK  :: 19
-MADV_HWPOISON    :: 100
-
-mmap :: proc "contextless" (addr: rawptr, length: uint, prot: c.int, flags: c.int, fd: c.int, offset: uintptr) -> int {
-	res := intrinsics.syscall(unix.SYS_mmap, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), offset)
-	return int(res)
-}
-
-munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int {
-	res := intrinsics.syscall(unix.SYS_munmap, uintptr(addr), uintptr(length))
-	return c.int(res)
-}
-
-mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int {
-	res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))
-	return c.int(res)
-}
-
-madvise :: proc "contextless" (addr: rawptr, length: uint, advice: c.int) -> c.int {
-	res := intrinsics.syscall(unix.SYS_madvise, uintptr(addr), uintptr(length), uintptr(advice))
-	return c.int(res)
-}
-
+import "core:sys/linux"
 
 _reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
-	result := mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
-	if result < 0 && result > -4096 {
+	addr, errno := linux.mmap(0, size, {}, {.PRIVATE, .ANONYMOUS})
+	if errno == .ENOMEM {
 		return nil, .Out_Of_Memory
+	} else if errno == .EINVAL {
+		return nil, .Invalid_Argument
 	}
-	return ([^]byte)(uintptr(result))[:size], nil
+	return (cast([^]byte)addr)[:size], nil
 }
 
 _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
-	result := mprotect(data, size, PROT_READ|PROT_WRITE)
-	if result != 0 {
-		// TODO(bill): Handle error value correctly
+	errno := linux.mprotect(data, size, {.READ, .WRITE})
+	if errno == .EINVAL {
+		return .Invalid_Pointer
+	} else if errno == .ENOMEM {
 		return .Out_Of_Memory
 	}
 	return nil
 }
+
 _decommit :: proc "contextless" (data: rawptr, size: uint) {
-	mprotect(data, size, PROT_NONE)
-	madvise(data, size, MADV_FREE)
+	_ = linux.mprotect(data, size, {})
+	_ = linux.madvise(data, size, .FREE)
 }
+
 _release :: proc "contextless" (data: rawptr, size: uint) {
-	munmap(data, size)
+	_ = linux.munmap(data, size)
 }
+
 _protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
-	pflags: c.int
-	pflags = PROT_NONE
-	if .Read    in flags { pflags |= PROT_READ  }
-	if .Write   in flags { pflags |= PROT_WRITE }
-	if .Execute in flags { pflags |= PROT_EXEC  }
-	err := mprotect(data, size, pflags)
-	return err != 0
+	pflags: linux.Mem_Protection
+	pflags = {}
+	if .Read    in flags { pflags |= {.READ}  }
+	if .Write   in flags { pflags |= {.WRITE} }
+	if .Execute in flags { pflags |= {.EXEC}  }
+	errno := linux.mprotect(data, size, pflags)
+	return errno != .NONE
 }
 
-
-
 _platform_memory_init :: proc() {
 	DEFAULT_PAGE_SIZE = 4096
-	
 	// is power of two
 	assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
 }

+ 95 - 93
core/net/errors_linux.odin

@@ -16,182 +16,184 @@ package net
 		Tetralux:        Initial implementation
 		Colin Davidson:  Linux platform code, OSX platform code, Odin-native DNS resolver
 		Jeroen van Rijn: Cross platform unification, code style, documentation
+		flysand:         Move dependency from core:linux.Errno to core:sys/linux
 */
 
 import "core:c"
-import "core:os"
+import "core:sys/linux"
 
 Create_Socket_Error :: enum c.int {
 	None                                 = 0,
-	Family_Not_Supported_For_This_Socket = c.int(os.EAFNOSUPPORT),
-	No_Socket_Descriptors_Available      = c.int(os.EMFILE),
-	No_Buffer_Space_Available            = c.int(os.ENOBUFS),
-	No_Memory_Available_Available        = c.int(os.ENOMEM),
-	Protocol_Unsupported_By_System       = c.int(os.EPROTONOSUPPORT),
-	Wrong_Protocol_For_Socket            = c.int(os.EPROTONOSUPPORT),
-	Family_And_Socket_Type_Mismatch      = c.int(os.EPROTONOSUPPORT),
+	Family_Not_Supported_For_This_Socket = c.int(linux.Errno.EAFNOSUPPORT),
+	No_Socket_Descriptors_Available      = c.int(linux.Errno.EMFILE),
+	No_Buffer_Space_Available            = c.int(linux.Errno.ENOBUFS),
+	No_Memory_Available_Available        = c.int(linux.Errno.ENOMEM),
+	Protocol_Unsupported_By_System       = c.int(linux.Errno.EPROTONOSUPPORT),
+	Wrong_Protocol_For_Socket            = c.int(linux.Errno.EPROTONOSUPPORT),
+	Family_And_Socket_Type_Mismatch      = c.int(linux.Errno.EPROTONOSUPPORT),
 }
 
 Dial_Error :: enum c.int {
 	None                      = 0,
 	Port_Required             = -1,
 
-	Address_In_Use            = c.int(os.EADDRINUSE),
-	In_Progress               = c.int(os.EINPROGRESS),
-	Cannot_Use_Any_Address    = c.int(os.EADDRNOTAVAIL),
-	Wrong_Family_For_Socket   = c.int(os.EAFNOSUPPORT),
-	Refused                   = c.int(os.ECONNREFUSED),
-	Is_Listening_Socket       = c.int(os.EACCES),
-	Already_Connected         = c.int(os.EISCONN),
-	Network_Unreachable       = c.int(os.ENETUNREACH), // Device is offline
-	Host_Unreachable          = c.int(os.EHOSTUNREACH), // Remote host cannot be reached
-	No_Buffer_Space_Available = c.int(os.ENOBUFS),
-	Not_Socket                = c.int(os.ENOTSOCK),
-	Timeout                   = c.int(os.ETIMEDOUT),
+	Address_In_Use            = c.int(linux.Errno.EADDRINUSE),
+	In_Progress               = c.int(linux.Errno.EINPROGRESS),
+	Cannot_Use_Any_Address    = c.int(linux.Errno.EADDRNOTAVAIL),
+	Wrong_Family_For_Socket   = c.int(linux.Errno.EAFNOSUPPORT),
+	Refused                   = c.int(linux.Errno.ECONNREFUSED),
+	Is_Listening_Socket       = c.int(linux.Errno.EACCES),
+	Already_Connected         = c.int(linux.Errno.EISCONN),
+	Network_Unreachable       = c.int(linux.Errno.ENETUNREACH), // Device is offline
+	Host_Unreachable          = c.int(linux.Errno.EHOSTUNREACH), // Remote host cannot be reached
+	No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS),
+	Not_Socket                = c.int(linux.Errno.ENOTSOCK),
+	Timeout                   = c.int(linux.Errno.ETIMEDOUT),
 
 	// TODO: we may need special handling for this; maybe make a socket a struct with metadata?
-	Would_Block               = c.int(os.EWOULDBLOCK), 
+	Would_Block               = c.int(linux.Errno.EWOULDBLOCK), 
 }
 
 Bind_Error :: enum c.int {
 	None                    = 0,
-	Address_In_Use          = c.int(os.EADDRINUSE),    // Another application is currently bound to this endpoint.
-	Given_Nonlocal_Address  = c.int(os.EADDRNOTAVAIL), // The address is not a local address on this machine.
-	Broadcast_Disabled      = c.int(os.EACCES),        // To bind a UDP socket to the broadcast address, the appropriate socket option must be set.
-	Address_Family_Mismatch = c.int(os.EFAULT),        // The address family of the address does not match that of the socket.
-	Already_Bound           = c.int(os.EINVAL),        // The socket is already bound to an address.
-	No_Ports_Available      = c.int(os.ENOBUFS),       // There are not enough ephemeral ports available.
+	Address_In_Use          = c.int(linux.Errno.EADDRINUSE),    // Another application is currently bound to this endpoint.
+	Given_Nonlocal_Address  = c.int(linux.Errno.EADDRNOTAVAIL), // The address is not a local address on this machine.
+	Broadcast_Disabled      = c.int(linux.Errno.EACCES),        // To bind a UDP socket to the broadcast address, the appropriate socket option must be set.
+	Address_Family_Mismatch = c.int(linux.Errno.EFAULT),        // The address family of the address does not match that of the socket.
+	Already_Bound           = c.int(linux.Errno.EINVAL),        // The socket is already bound to an address.
+	No_Ports_Available      = c.int(linux.Errno.ENOBUFS),       // There are not enough ephemeral ports available.
 }
 
 Listen_Error :: enum c.int {
 	None                                    = 0,
-	Address_In_Use                          = c.int(os.EADDRINUSE),
-	Already_Connected                       = c.int(os.EISCONN),
-	No_Socket_Descriptors_Available         = c.int(os.EMFILE),
-	No_Buffer_Space_Available               = c.int(os.ENOBUFS),
-	Nonlocal_Address                        = c.int(os.EADDRNOTAVAIL),
-	Not_Socket                              = c.int(os.ENOTSOCK),
-	Listening_Not_Supported_For_This_Socket = c.int(os.EOPNOTSUPP),
+	Address_In_Use                          = c.int(linux.Errno.EADDRINUSE),
+	Already_Connected                       = c.int(linux.Errno.EISCONN),
+	No_Socket_Descriptors_Available         = c.int(linux.Errno.EMFILE),
+	No_Buffer_Space_Available               = c.int(linux.Errno.ENOBUFS),
+	Nonlocal_Address                        = c.int(linux.Errno.EADDRNOTAVAIL),
+	Not_Socket                              = c.int(linux.Errno.ENOTSOCK),
+	Listening_Not_Supported_For_This_Socket = c.int(linux.Errno.EOPNOTSUPP),
 }
 
 Accept_Error :: enum c.int {
 	None                                              = 0,
-	Not_Listening                                     = c.int(os.EINVAL),
-	No_Socket_Descriptors_Available_For_Client_Socket = c.int(os.EMFILE),
-	No_Buffer_Space_Available                         = c.int(os.ENOBUFS),
-	Not_Socket                                        = c.int(os.ENOTSOCK),
-	Not_Connection_Oriented_Socket                    = c.int(os.EOPNOTSUPP),
+	Not_Listening                                     = c.int(linux.Errno.EINVAL),
+	No_Socket_Descriptors_Available_For_Client_Socket = c.int(linux.Errno.EMFILE),
+	No_Buffer_Space_Available                         = c.int(linux.Errno.ENOBUFS),
+	Not_Socket                                        = c.int(linux.Errno.ENOTSOCK),
+	Not_Connection_Oriented_Socket                    = c.int(linux.Errno.EOPNOTSUPP),
 
 	// TODO: we may need special handling for this; maybe make a socket a struct with metadata?
-	Would_Block                                       = c.int(os.EWOULDBLOCK),
+	Would_Block                                       = c.int(linux.Errno.EWOULDBLOCK),
 }
 
 TCP_Recv_Error :: enum c.int {
 	None              = 0,
-	Shutdown          = c.int(os.ESHUTDOWN),
-	Not_Connected     = c.int(os.ENOTCONN),
-	Connection_Broken = c.int(os.ENETRESET),
-	Not_Socket        = c.int(os.ENOTSOCK),
-	Aborted           = c.int(os.ECONNABORTED),
+	Shutdown          = c.int(linux.Errno.ESHUTDOWN),
+	Not_Connected     = c.int(linux.Errno.ENOTCONN),
+	Connection_Broken = c.int(linux.Errno.ENETRESET),
+	Not_Socket        = c.int(linux.Errno.ENOTSOCK),
+	Aborted           = c.int(linux.Errno.ECONNABORTED),
 
 	// TODO(tetra): Determine when this is different from the syscall returning n=0 and maybe normalize them?
-	Connection_Closed = c.int(os.ECONNRESET), 
-	Offline           = c.int(os.ENETDOWN),
-	Host_Unreachable  = c.int(os.EHOSTUNREACH),
-	Interrupted       = c.int(os.EINTR),
-	Timeout           = c.int(os.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets...
+	Connection_Closed = c.int(linux.Errno.ECONNRESET), 
+	Offline           = c.int(linux.Errno.ENETDOWN),
+	Host_Unreachable  = c.int(linux.Errno.EHOSTUNREACH),
+	Interrupted       = c.int(linux.Errno.EINTR),
+	Timeout           = c.int(linux.Errno.EWOULDBLOCK), // NOTE: No, really. Presumably this means something different for nonblocking sockets...
 }
 
 UDP_Recv_Error :: enum c.int {
 	None             = 0,
 
-	Buffer_Too_Small = c.int(os.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
-	Not_Socket       = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
-	Not_Descriptor   = c.int(os.EBADF),    // The so-called socket is, in fact, not even a valid descriptor.
-	Bad_Buffer       = c.int(os.EFAULT),   // The buffer did not point to a valid location in memory.
-	Interrupted      = c.int(os.EINTR),    // A signal occurred before any data was transmitted. See signal(7).
+	Buffer_Too_Small = c.int(linux.Errno.EMSGSIZE), // The buffer is too small to fit the entire message, and the message was truncated. When this happens, the rest of message is lost.
+	Not_Socket       = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket.
+	Not_Descriptor   = c.int(linux.Errno.EBADF),    // The so-called socket is, in fact, not even a valid descriptor.
+	Bad_Buffer       = c.int(linux.Errno.EFAULT),   // The buffer did not point to a valid location in memory.
+	Interrupted      = c.int(linux.Errno.EINTR),    // A signal occurred before any data was transmitted. See signal(7).
 
 	// The send timeout duration passed before all data was received. See Socket_Option.Receive_Timeout.
 	// NOTE: No, really. Presumably this means something different for nonblocking sockets...
-	Timeout          = c.int(os.EWOULDBLOCK), 
-	Socket_Not_Bound = c.int(os.EINVAL), // The socket must be bound for this operation, but isn't.
+	Timeout          = c.int(linux.Errno.EWOULDBLOCK), 
+	Socket_Not_Bound = c.int(linux.Errno.EINVAL), // The socket must be bound for this operation, but isn't.
 }
 
 TCP_Send_Error :: enum c.int {
 	None                      = 0,
-	Aborted                   = c.int(os.ECONNABORTED), 
-	Connection_Closed         = c.int(os.ECONNRESET),
-	Not_Connected             = c.int(os.ENOTCONN),
-	Shutdown                  = c.int(os.ESHUTDOWN),
+	Aborted                   = c.int(linux.Errno.ECONNABORTED), 
+	Connection_Closed         = c.int(linux.Errno.ECONNRESET),
+	Not_Connected             = c.int(linux.Errno.ENOTCONN),
+	Shutdown                  = c.int(linux.Errno.ESHUTDOWN),
 
 	// The send queue was full.
 	// This is usually a transient issue.
 	//
 	// This also shouldn't normally happen on Linux, as data is dropped if it
 	// doesn't fit in the send queue.
-	No_Buffer_Space_Available = c.int(os.ENOBUFS),
-	Offline                   = c.int(os.ENETDOWN),
-	Host_Unreachable          = c.int(os.EHOSTUNREACH),
-	Interrupted               = c.int(os.EINTR),        // A signal occurred before any data was transmitted. See signal(7).
-	Timeout                   = c.int(os.EWOULDBLOCK),  // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
-	Not_Socket                = c.int(os.ENOTSOCK),     // The so-called socket is not an open socket.
+	No_Buffer_Space_Available = c.int(linux.Errno.ENOBUFS),
+	Offline                   = c.int(linux.Errno.ENETDOWN),
+	Host_Unreachable          = c.int(linux.Errno.EHOSTUNREACH),
+	Interrupted               = c.int(linux.Errno.EINTR),        // A signal occurred before any data was transmitted. See signal(7).
+	Timeout                   = c.int(linux.Errno.EWOULDBLOCK),  // The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
+	Not_Socket                = c.int(linux.Errno.ENOTSOCK),     // The so-called socket is not an open socket.
 }
 
 // TODO
 UDP_Send_Error :: enum c.int {
 	None                        = 0,
-	Message_Too_Long            = c.int(os.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
+	Message_Too_Long            = c.int(linux.Errno.EMSGSIZE), // The message is larger than the maximum UDP packet size. No data was sent.
 
 	// TODO: not sure what the exact circumstances for this is yet
-	Network_Unreachable         = c.int(os.ENETUNREACH), 
-	No_Outbound_Ports_Available = c.int(os.EAGAIN),      // There are no more emphemeral outbound ports available to bind the socket to, in order to send.
+	Network_Unreachable         = c.int(linux.Errno.ENETUNREACH), 
+	No_Outbound_Ports_Available = c.int(linux.Errno.EAGAIN),      // There are no more emphemeral outbound ports available to bind the socket to, in order to send.
 
 	// The send timeout duration passed before all data was sent. See Socket_Option.Send_Timeout.
 	// NOTE: No, really. Presumably this means something different for nonblocking sockets...
-	Timeout                     = c.int(os.EWOULDBLOCK), 
-	Not_Socket                  = c.int(os.ENOTSOCK), // The so-called socket is not an open socket.
-	Not_Descriptor              = c.int(os.EBADF),    // The so-called socket is, in fact, not even a valid descriptor.
-	Bad_Buffer                  = c.int(os.EFAULT),   // The buffer did not point to a valid location in memory.
-	Interrupted                 = c.int(os.EINTR),    // A signal occurred before any data was transmitted. See signal(7).
+	Timeout                     = c.int(linux.Errno.EWOULDBLOCK), 
+	Not_Socket                  = c.int(linux.Errno.ENOTSOCK), // The so-called socket is not an open socket.
+	Not_Descriptor              = c.int(linux.Errno.EBADF),    // The so-called socket is, in fact, not even a valid descriptor.
+	Bad_Buffer                  = c.int(linux.Errno.EFAULT),   // The buffer did not point to a valid location in memory.
+	Interrupted                 = c.int(linux.Errno.EINTR),    // A signal occurred before any data was transmitted. See signal(7).
 
 	// The send queue was full.
 	// This is usually a transient issue.
 	//
 	// This also shouldn't normally happen on Linux, as data is dropped if it
 	// doesn't fit in the send queue.
-	No_Buffer_Space_Available   = c.int(os.ENOBUFS),
-	No_Memory_Available         = c.int(os.ENOMEM), // No memory was available to properly manage the send queue.
+	No_Buffer_Space_Available   = c.int(linux.Errno.ENOBUFS),
+	No_Memory_Available         = c.int(linux.Errno.ENOMEM), // No memory was available to properly manage the send queue.
 }
 
+// TODO(flysand): slight regression
 Shutdown_Manner :: enum c.int {
-	Receive = c.int(os.SHUT_RD),
-	Send    = c.int(os.SHUT_WR),
-	Both    = c.int(os.SHUT_RDWR),
+	Receive = c.int(linux.Shutdown_How.RD),
+	Send    = c.int(linux.Shutdown_How.WR),
+	Both    = c.int(linux.Shutdown_How.RDWR),
 }
 
 Shutdown_Error :: enum c.int {
 	None           = 0,
-	Aborted        = c.int(os.ECONNABORTED),
-	Reset          = c.int(os.ECONNRESET),
-	Offline        = c.int(os.ENETDOWN),
-	Not_Connected  = c.int(os.ENOTCONN),
-	Not_Socket     = c.int(os.ENOTSOCK),
-	Invalid_Manner = c.int(os.EINVAL),
+	Aborted        = c.int(linux.Errno.ECONNABORTED),
+	Reset          = c.int(linux.Errno.ECONNRESET),
+	Offline        = c.int(linux.Errno.ENETDOWN),
+	Not_Connected  = c.int(linux.Errno.ENOTCONN),
+	Not_Socket     = c.int(linux.Errno.ENOTSOCK),
+	Invalid_Manner = c.int(linux.Errno.EINVAL),
 }
 
 Socket_Option_Error :: enum c.int {
 	None                       = 0,
-	Offline                    = c.int(os.ENETDOWN),
-	Timeout_When_Keepalive_Set = c.int(os.ENETRESET),
-	Invalid_Option_For_Socket  = c.int(os.ENOPROTOOPT),
-	Reset_When_Keepalive_Set   = c.int(os.ENOTCONN),
-	Not_Socket                 = c.int(os.ENOTSOCK),
+	Offline                    = c.int(linux.Errno.ENETDOWN),
+	Timeout_When_Keepalive_Set = c.int(linux.Errno.ENETRESET),
+	Invalid_Option_For_Socket  = c.int(linux.Errno.ENOPROTOOPT),
+	Reset_When_Keepalive_Set   = c.int(linux.Errno.ENOTCONN),
+	Not_Socket                 = c.int(linux.Errno.ENOTSOCK),
 }
 
 Set_Blocking_Error :: enum c.int {
 	None = 0,
 
 	// TODO: add errors occuring on followig calls:
-	// flags, _ := os.fcntl(sd, os.F_GETFL, 0)
-	// os.fcntl(sd, os.F_SETFL, flags | int(os.O_NONBLOCK))
+	// flags, _ := linux.Errno.fcntl(sd, linux.Errno.F_GETFL, 0)
+	// linux.Errno.fcntl(sd, linux.Errno.F_SETFL, flags | int(linux.Errno.O_NONBLOCK))
 }

+ 115 - 111
core/net/interface_linux.odin

@@ -21,120 +21,124 @@ package net
 	TODO: When we have raw sockets, split off into its own file for Linux so we can use the NETLINK protocol and bypass libc.
 */
 
-import "core:os"
-import "core:strings"
+//import "core:strings"
 
+
+// TODO(flysand): regression
+// NOTE(flysand): https://man7.org/linux/man-pages/man7/netlink.7.html
+// apparently musl libc uses this to enumerate network interfaces
 @(private)
 _enumerate_interfaces :: proc(allocator := context.allocator) -> (interfaces: []Network_Interface, err: Network_Error) {
 	context.allocator = allocator
 
-	head: ^os.ifaddrs
-
-	if res := os._getifaddrs(&head); res < 0 {
-		return {}, .Unable_To_Enumerate_Network_Interfaces
-	}
-
-	/*
-		Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct.
-		We're going to have to iterate over a list and coalesce information as we go.
-	*/
-	ifaces: map[string]^Network_Interface
-	defer delete(ifaces)
-
-	for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next {
-		adapter_name := string(ifaddr.name)
-
-		/*
-			Check if we have seen this interface name before so we can reuse the `Network_Interface`.
-			Else, create a new one.
-		*/
-		if adapter_name not_in ifaces {
-			ifaces[adapter_name] = new(Network_Interface)
-			ifaces[adapter_name].adapter_name = strings.clone(adapter_name)
-		}
-		iface := ifaces[adapter_name]
-
-		address: Address
-		netmask: Netmask
-
-		if ifaddr.address != nil {
-			switch int(ifaddr.address.sa_family) {
-			case os.AF_INET, os.AF_INET6:
-				address = _sockaddr_basic_to_endpoint(ifaddr.address).address
-
-			case os.AF_PACKET:
-				/*
-					For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a
-					32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count
-					is truncated beyond usefulness.
-
-					We're not going to retrieve stats now. Instead this serves as a reminder to use
-					the NETLINK protocol for this purpose.
-
-					But in case you were curious:
-						stats := transmute(^os.rtnl_link_stats)ifaddr.data
-						fmt.println(stats)
-				*/
-			case:
-			}
-		}
-
-		if ifaddr.netmask != nil {
-			switch int(ifaddr.netmask.sa_family) {
-			case os.AF_INET, os.AF_INET6:
-			 	netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address)
-			case:
-			}
-		}
-
-		if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags {
-			switch int(ifaddr.broadcast_or_dest.sa_family) {
-			case os.AF_INET, os.AF_INET6:
-			 	broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address
-			 	append(&iface.multicast, broadcast)
-			case:
-			}
-		}
-
-		if address != nil {
-			lease := Lease{
-				address = address,
-				netmask = netmask,
-			}
-			append(&iface.unicast, lease)
-		}
-
-		/*
-			TODO: Refine this based on the type of adapter.
-		*/
- 		state := Link_State{}
-
- 		if .UP in ifaddr.flags {
- 			state |= {.Up}
- 		}
-
- 		if .DORMANT in ifaddr.flags {
- 			state |= {.Dormant}
- 		}
-
- 		if .LOOPBACK in ifaddr.flags {
- 			state |= {.Loopback}
- 		}
-		iface.link.state = state
-	}
-
-	/*
-		Free the OS structures.
-	*/
-	os._freeifaddrs(head)
-
-	/*
-		Turn the map into a slice to return.
-	*/
-	_interfaces := make([dynamic]Network_Interface, 0, allocator)
-	for _, iface in ifaces {
-		append(&_interfaces, iface^)
-		free(iface)
-	}
-	return _interfaces[:], {}
+	// head: ^os.ifaddrs
+
+	// if res := os._getifaddrs(&head); res < 0 {
+	// 	return {}, .Unable_To_Enumerate_Network_Interfaces
+	// }
+
+	// /*
+	// 	Unlike Windows, *nix regrettably doesn't return all it knows about an interface in one big struct.
+	// 	We're going to have to iterate over a list and coalesce information as we go.
+	// */
+	// ifaces: map[string]^Network_Interface
+	// defer delete(ifaces)
+
+	// for ifaddr := head; ifaddr != nil; ifaddr = ifaddr.next {
+	// 	adapter_name := string(ifaddr.name)
+
+	// 	/*
+	// 		Check if we have seen this interface name before so we can reuse the `Network_Interface`.
+	// 		Else, create a new one.
+	// 	*/
+	// 	if adapter_name not_in ifaces {
+	// 		ifaces[adapter_name] = new(Network_Interface)
+	// 		ifaces[adapter_name].adapter_name = strings.clone(adapter_name)
+	// 	}
+	// 	iface := ifaces[adapter_name]
+
+	// 	address: Address
+	// 	netmask: Netmask
+
+	// 	if ifaddr.address != nil {
+	// 		switch int(ifaddr.address.sa_family) {
+	// 		case os.AF_INET, os.AF_INET6:
+	// 			address = _sockaddr_basic_to_endpoint(ifaddr.address).address
+
+	// 		case os.AF_PACKET:
+	// 			/*
+	// 				For some obscure reason the 64-bit `getifaddrs` call returns a pointer to a
+	// 				32-bit `RTNL_LINK_STATS` structure, which of course means that tx/rx byte count
+	// 				is truncated beyond usefulness.
+
+	// 				We're not going to retrieve stats now. Instead this serves as a reminder to use
+	// 				the NETLINK protocol for this purpose.
+
+	// 				But in case you were curious:
+	// 					stats := transmute(^os.rtnl_link_stats)ifaddr.data
+	// 					fmt.println(stats)
+	// 			*/
+	// 		case:
+	// 		}
+	// 	}
+
+	// 	if ifaddr.netmask != nil {
+	// 		switch int(ifaddr.netmask.sa_family) {
+	// 		case os.AF_INET, os.AF_INET6:
+	// 		 	netmask = Netmask(_sockaddr_basic_to_endpoint(ifaddr.netmask).address)
+	// 		case:
+	// 		}
+	// 	}
+
+	// 	if ifaddr.broadcast_or_dest != nil && .BROADCAST in ifaddr.flags {
+	// 		switch int(ifaddr.broadcast_or_dest.sa_family) {
+	// 		case os.AF_INET, os.AF_INET6:
+	// 		 	broadcast := _sockaddr_basic_to_endpoint(ifaddr.broadcast_or_dest).address
+	// 		 	append(&iface.multicast, broadcast)
+	// 		case:
+	// 		}
+	// 	}
+
+	// 	if address != nil {
+	// 		lease := Lease{
+	// 			address = address,
+	// 			netmask = netmask,
+	// 		}
+	// 		append(&iface.unicast, lease)
+	// 	}
+
+	// 	/*
+	// 		TODO: Refine this based on the type of adapter.
+	// 	*/
+ 	// 	state := Link_State{}
+
+ 	// 	if .UP in ifaddr.flags {
+ 	// 		state |= {.Up}
+ 	// 	}
+
+ 	// 	if .DORMANT in ifaddr.flags {
+ 	// 		state |= {.Dormant}
+ 	// 	}
+
+ 	// 	if .LOOPBACK in ifaddr.flags {
+ 	// 		state |= {.Loopback}
+ 	// 	}
+	// 	iface.link.state = state
+	// }
+
+	// /*
+	// 	Free the OS structures.
+	// */
+	// os._freeifaddrs(head)
+
+	// /*
+	// 	Turn the map into a slice to return.
+	// */
+	// _interfaces := make([dynamic]Network_Interface, 0, allocator)
+	// for _, iface in ifaces {
+	// 	append(&_interfaces, iface^)
+	// 	free(iface)
+	// }
+	// return _interfaces[:], {}
+	return nil, {}
 }

+ 1 - 1
core/net/socket.odin

@@ -18,7 +18,7 @@ package net
 		Jeroen van Rijn: Cross platform unification, code style, documentation
 */
 
-any_socket_to_socket :: proc(socket: Any_Socket) -> Socket {
+any_socket_to_socket :: proc "contextless" (socket: Any_Socket) -> Socket {
 	switch s in socket {
 	case TCP_Socket:  return Socket(s)
 	case UDP_Socket:  return Socket(s)

+ 221 - 245
core/net/socket_linux.odin

@@ -16,241 +16,294 @@ package net
 		Tetralux:        Initial implementation
 		Colin Davidson:  Linux platform code, OSX platform code, Odin-native DNS resolver
 		Jeroen van Rijn: Cross platform unification, code style, documentation
+		flysand:         Move dependency from core:os to core:sys/linux
 */
 
 import "core:c"
-import "core:os"
 import "core:time"
+import "core:sys/linux"
 
 Socket_Option :: enum c.int {
-	Reuse_Address             = c.int(os.SO_REUSEADDR),
-	Keep_Alive                = c.int(os.SO_KEEPALIVE),
-	Out_Of_Bounds_Data_Inline = c.int(os.SO_OOBINLINE),
-	TCP_Nodelay               = c.int(os.TCP_NODELAY),
-	Linger                    = c.int(os.SO_LINGER),
-	Receive_Buffer_Size       = c.int(os.SO_RCVBUF),
-	Send_Buffer_Size          = c.int(os.SO_SNDBUF),
-	Receive_Timeout           = c.int(os.SO_RCVTIMEO_NEW),
-	Send_Timeout              = c.int(os.SO_SNDTIMEO_NEW),
+	Reuse_Address             = c.int(linux.Socket_Option.REUSEADDR),
+	Keep_Alive                = c.int(linux.Socket_Option.KEEPALIVE),
+	Out_Of_Bounds_Data_Inline = c.int(linux.Socket_Option.OOBINLINE),
+	TCP_Nodelay               = c.int(linux.Socket_TCP_Option.NODELAY),
+	Linger                    = c.int(linux.Socket_Option.LINGER),
+	Receive_Buffer_Size       = c.int(linux.Socket_Option.RCVBUF),
+	Send_Buffer_Size          = c.int(linux.Socket_Option.SNDBUF),
+	Receive_Timeout           = c.int(linux.Socket_Option.RCVTIMEO_NEW),
+	Send_Timeout              = c.int(linux.Socket_Option.SNDTIMEO_NEW),
 }
 
-@(private)
-_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (socket: Any_Socket, err: Network_Error) {
-	c_type, c_protocol, c_family: int
+// Wrappers and unwrappers for system-native types
+
+@(private="file")
+_unwrap_os_socket :: proc "contextless" (sock: Any_Socket)->linux.Fd {
+	return linux.Fd(any_socket_to_socket(sock))
+}
 
+@(private="file")
+_wrap_os_socket :: proc "contextless" (sock: linux.Fd, protocol: Socket_Protocol)->Any_Socket {
+	switch protocol {
+	case .TCP:  return TCP_Socket(Socket(sock))
+	case .UDP:  return UDP_Socket(Socket(sock))
+	case:
+		unreachable()
+	}
+}
+
+@(private="file")
+_unwrap_os_family :: proc "contextless" (family: Address_Family)->linux.Address_Family {
 	switch family {
-	case .IP4:  c_family = os.AF_INET
-	case .IP6:  c_family = os.AF_INET6
+	case .IP4:  return .INET
+	case .IP6:  return .INET6
 	case:
 		unreachable()
 	}
+}
 
+@(private="file")
+_unwrap_os_proto_socktype :: proc "contextless" (protocol: Socket_Protocol)->(linux.Protocol, linux.Socket_Type) {
 	switch protocol {
-	case .TCP:  c_type = os.SOCK_STREAM; c_protocol = os.IPPROTO_TCP
-	case .UDP:  c_type = os.SOCK_DGRAM;  c_protocol = os.IPPROTO_UDP
+	case .TCP:  return .TCP, .STREAM
+	case .UDP:  return .UDP, .DGRAM
 	case:
 		unreachable()
 	}
+}
 
-	sock, ok := os.socket(c_family, c_type, c_protocol)
-	if ok != os.ERROR_NONE {
-		err = Create_Socket_Error(ok)
-		return
+@(private="file")
+_unwrap_os_addr :: proc "contextless" (endpoint: Endpoint)->(linux.Sock_Addr_Any) {
+	switch address in endpoint.address {
+	case IP4_Address:
+		return {
+			ipv4 = {
+				sin_family = .INET,
+				sin_port = u16be(endpoint.port),
+				sin_addr = transmute([4]u8) endpoint.address.(IP4_Address),
+			},
+		}
+	case IP6_Address:
+		return {
+			ipv6 = {
+				sin6_port = u16be(endpoint.port),
+				sin6_addr = transmute([16]u8) endpoint.address.(IP6_Address),
+				sin6_family = .INET6,
+			},
+		}
+	case:
+		unreachable()
 	}
+}
 
-	switch protocol {
-	case .TCP:  return TCP_Socket(sock), nil
-	case .UDP:  return UDP_Socket(sock), nil
+@(private="file")
+_wrap_os_addr :: proc "contextless" (addr: linux.Sock_Addr_Any)->(Endpoint) {
+	#partial switch addr.family {
+	case .INET:
+		return {
+			address = cast(IP4_Address) addr.sin_addr,
+			port = cast(int) addr.sin_port,
+		}
+	case .INET6:
+		return {
+			port = cast(int) addr.sin6_port,
+			address = transmute(IP6_Address) addr.sin6_addr,
+		}
 	case:
 		unreachable()
 	}
 }
 
+_create_socket :: proc(family: Address_Family, protocol: Socket_Protocol) -> (Any_Socket, Network_Error) {
+	family := _unwrap_os_family(family)
+	proto, socktype := _unwrap_os_proto_socktype(protocol)
+	sock, errno := linux.socket(family, socktype, {}, proto)
+	if errno != .NONE {
+		return {}, Create_Socket_Error(errno)
+	}
+	return _wrap_os_socket(sock, protocol), nil
+}
+
 @(private)
-_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (skt: TCP_Socket, err: Network_Error) {
+_dial_tcp_from_endpoint :: proc(endpoint: Endpoint, options := default_tcp_options) -> (tcp_sock: TCP_Socket, err: Network_Error) {
+	errno: linux.Errno
 	if endpoint.port == 0 {
 		return 0, .Port_Required
 	}
-
-	family := family_from_endpoint(endpoint)
-	sock := create_socket(family, .TCP) or_return
-	skt = sock.(TCP_Socket)
-
+	// Create new TCP socket
+	os_sock: linux.Fd
+	os_sock, errno = linux.socket(_unwrap_os_family(family_from_endpoint(endpoint)), .STREAM, {}, .TCP)
+	if errno != .NONE {
+		// TODO(flysand): should return invalid file descriptor here casted as TCP_Socket
+		return {}, Create_Socket_Error(errno)
+	}
 	// NOTE(tetra): This is so that if we crash while the socket is open, we can
 	// bypass the cooldown period, and allow the next run of the program to
 	// use the same address immediately.
-	_ = set_option(skt, .Reuse_Address, true)
-
-	sockaddr := _endpoint_to_sockaddr(endpoint)
-	res := os.connect(os.Socket(skt), (^os.SOCKADDR)(&sockaddr), size_of(sockaddr))
-	if res != os.ERROR_NONE {
-		err = Dial_Error(res)
-		return
+	reuse_addr: b32 = true
+	_ = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &reuse_addr)
+	addr := _unwrap_os_addr(endpoint)
+	errno = linux.connect(linux.Fd(tcp_sock), &addr)
+	if errno != .NONE {
+		return cast(TCP_Socket) os_sock, Dial_Error(errno)
 	}
-
-	if options.no_delay {
-		_ = _set_option(sock, .TCP_Nodelay, true) // NOTE(tetra): Not vital to succeed; error ignored
-	}
-
-	return
+	// NOTE(tetra): Not vital to succeed; error ignored
+	no_delay: b32 = cast(b32) options.no_delay
+	_ = linux.setsockopt(os_sock, linux.SOL_TCP, linux.Socket_TCP_Option.NODELAY, &no_delay)
+	return cast(TCP_Socket) os_sock, nil
 }
 
 @(private)
-_bind :: proc(skt: Any_Socket, ep: Endpoint) -> (err: Network_Error) {
-	sockaddr := _endpoint_to_sockaddr(ep)
-	s := any_socket_to_socket(skt)
-	res := os.bind(os.Socket(s), (^os.SOCKADDR)(&sockaddr), size_of(sockaddr))
-	if res != os.ERROR_NONE {
-		err = Bind_Error(res)
+_bind :: proc(sock: Any_Socket, endpoint: Endpoint) -> (Network_Error) {
+	addr := _unwrap_os_addr(endpoint)
+	errno := linux.bind(_unwrap_os_socket(sock), &addr)
+	if errno != .NONE {
+		return Bind_Error(errno)
 	}
-	return
+	return nil
 }
 
 @(private)
-_listen_tcp :: proc(interface_endpoint: Endpoint, backlog := 1000) -> (skt: TCP_Socket, err: Network_Error) {
+_listen_tcp :: proc(endpoint: Endpoint, backlog := 1000) -> (TCP_Socket, Network_Error) {
+	errno: linux.Errno
 	assert(backlog > 0 && i32(backlog) < max(i32))
-
-	family := family_from_endpoint(interface_endpoint)
-	sock := create_socket(family, .TCP) or_return
-	skt = sock.(TCP_Socket)
-
+	// Figure out the address family and address of the endpoint
+	ep_family := _unwrap_os_family(family_from_endpoint(endpoint))
+	ep_address := _unwrap_os_addr(endpoint)
+	// Create TCP socket
+	os_sock: linux.Fd
+	os_sock, errno = linux.socket(ep_family, .STREAM, {}, .TCP)
+	if errno != .NONE {
+		// TODO(flysand): should return invalid file descriptor here casted as TCP_Socket
+		return {}, Create_Socket_Error(errno)
+	}
 	// NOTE(tetra): This is so that if we crash while the socket is open, we can
 	// bypass the cooldown period, and allow the next run of the program to
 	// use the same address immediately.
 	//
 	// TODO(tetra, 2022-02-15): Confirm that this doesn't mean other processes can hijack the address!
-	set_option(sock, .Reuse_Address, true) or_return
-
-	bind(sock, interface_endpoint) or_return
-
-	res := os.listen(os.Socket(skt), backlog)
-	if res != os.ERROR_NONE {
-		err = Listen_Error(res)
-		return
+	do_reuse_addr: b32 = true
+	errno = linux.setsockopt(os_sock, linux.SOL_SOCKET, linux.Socket_Option.REUSEADDR, &do_reuse_addr)
+	if errno != .NONE {
+		return cast(TCP_Socket) os_sock, Listen_Error(errno)
 	}
-
-	return
+	// Bind the socket to endpoint address
+	errno = linux.bind(os_sock, &ep_address)
+	if errno != .NONE {
+		return cast(TCP_Socket) os_sock, Bind_Error(errno)
+	}
+	// Listen on bound socket
+	errno = linux.listen(os_sock, cast(i32) backlog)
+	if errno != .NONE {
+		return cast(TCP_Socket) os_sock, Listen_Error(errno)
+	}
+	return cast(TCP_Socket) os_sock, nil
 }
 
 @(private)
-_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (client: TCP_Socket, source: Endpoint, err: Network_Error) {
-	sockaddr: os.SOCKADDR_STORAGE_LH
-	sockaddrlen := c.int(size_of(sockaddr))
-
-	client_sock, ok := os.accept(os.Socket(sock), cast(^os.SOCKADDR) &sockaddr, &sockaddrlen)
-	if ok != os.ERROR_NONE {
-		err = Accept_Error(ok)
-		return
+_accept_tcp :: proc(sock: TCP_Socket, options := default_tcp_options) -> (tcp_client: TCP_Socket, endpoint: Endpoint, err: Network_Error) {
+	addr: linux.Sock_Addr_Any
+	client_sock, errno := linux.accept(linux.Fd(sock), &addr)
+	if errno != .NONE {
+		return {}, {}, Accept_Error(errno)
 	}
-	client = TCP_Socket(client_sock)
-	source = _sockaddr_storage_to_endpoint(&sockaddr)
-	if options.no_delay {
-		_ = _set_option(client, .TCP_Nodelay, true) // NOTE(tetra): Not vital to succeed; error ignored
-	}
-	return
+	// NOTE(tetra): Not vital to succeed; error ignored
+	val: b32 = cast(b32) options.no_delay
+	_ = linux.setsockopt(client_sock, linux.SOL_TCP, linux.Socket_TCP_Option.NODELAY, &val)
+	return TCP_Socket(client_sock), _wrap_os_addr(addr), nil
 }
 
 @(private)
-_close :: proc(skt: Any_Socket) {
-	s := any_socket_to_socket(skt)
-	os.close(os.Handle(os.Socket(s)))
+_close :: proc(sock: Any_Socket) {
+	linux.close(_unwrap_os_socket(sock))
 }
 
 @(private)
-_recv_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_read: int, err: Network_Error) {
+_recv_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) {
 	if len(buf) <= 0 {
-		return
+		return 0, nil
 	}
-	res, ok := os.recv(os.Socket(skt), buf, 0)
-	if ok != os.ERROR_NONE {
-		err = TCP_Recv_Error(ok)
-		return
+	bytes_read, errno := linux.recv(linux.Fd(tcp_sock), buf, {})
+	if errno != .NONE {
+		return 0, TCP_Recv_Error(errno)
 	}
-	return int(res), nil
+	return int(bytes_read), nil
 }
 
 @(private)
-_recv_udp :: proc(skt: UDP_Socket, buf: []byte) -> (bytes_read: int, remote_endpoint: Endpoint, err: Network_Error) {
+_recv_udp :: proc(udp_sock: UDP_Socket, buf: []byte) -> (int, Endpoint, Network_Error) {
 	if len(buf) <= 0 {
-		return
+		// NOTE(flysand): It was returning no error, I didn't change anything
+		return 0, {}, {}
 	}
-
-	from: os.SOCKADDR_STORAGE_LH = ---
-	fromsize := c.int(size_of(from))
-
 	// NOTE(tetra): On Linux, if the buffer is too small to fit the entire datagram payload, the rest is silently discarded,
 	// and no error is returned.
 	// However, if you pass MSG_TRUNC here, 'res' will be the size of the incoming message, rather than how much was read.
 	// We can use this fact to detect this condition and return .Buffer_Too_Small.
-	res, ok := os.recvfrom(os.Socket(skt), buf, os.MSG_TRUNC, cast(^os.SOCKADDR) &from, &fromsize)
-	if ok != os.ERROR_NONE {
-		err = UDP_Recv_Error(ok)
-		return
+	from_addr: linux.Sock_Addr_Any
+	bytes_read, errno := linux.recvfrom(linux.Fd(udp_sock), buf, {.TRUNC}, &from_addr)
+	if errno != .NONE {
+		return 0, {}, UDP_Recv_Error(errno)
 	}
-
-	bytes_read = int(res)
-	remote_endpoint = _sockaddr_storage_to_endpoint(&from)
-
 	if bytes_read > len(buf) {
 		// NOTE(tetra): The buffer has been filled, with a partial message.
-		bytes_read = len(buf)
-		err = .Buffer_Too_Small
+		return len(buf), {}, .Buffer_Too_Small
 	}
-
-	return
+	return bytes_read, _wrap_os_addr(from_addr), nil
 }
 
 @(private)
-_send_tcp :: proc(skt: TCP_Socket, buf: []byte) -> (bytes_written: int, err: Network_Error) {
-	for bytes_written < len(buf) {
-		limit := min(int(max(i32)), len(buf) - bytes_written)
-		remaining := buf[bytes_written:][:limit]
-		res, ok := os.send(os.Socket(skt), remaining, 0)
-		if ok != os.ERROR_NONE {
-			err = TCP_Send_Error(ok)
-			return
+_send_tcp :: proc(tcp_sock: TCP_Socket, buf: []byte) -> (int, Network_Error) {
+	total_written := 0
+	for total_written < len(buf) {
+		limit := min(int(max(i32)), len(buf) - total_written)
+		remaining := buf[total_written:][:limit]
+		res, errno := linux.send(linux.Fd(tcp_sock), remaining, {})
+		if errno != .NONE {
+			return total_written, TCP_Send_Error(errno)
 		}
-		bytes_written += int(res)
+		total_written += int(res)
 	}
-	return
+	return total_written, nil
 }
 
 @(private)
-_send_udp :: proc(skt: UDP_Socket, buf: []byte, to: Endpoint) -> (bytes_written: int, err: Network_Error) {
-	toaddr := _endpoint_to_sockaddr(to)
-	res, os_err := os.sendto(os.Socket(skt), buf, 0, cast(^os.SOCKADDR) &toaddr, size_of(toaddr))
-	if os_err != os.ERROR_NONE {
-		err = UDP_Send_Error(os_err)
-		return
+_send_udp :: proc(udp_sock: UDP_Socket, buf: []byte, to: Endpoint) -> (int, Network_Error) {
+	to_addr := _unwrap_os_addr(to)
+	bytes_written, errno := linux.sendto(linux.Fd(udp_sock), buf, {}, &to_addr)
+	if errno != .NONE {
+		return bytes_written, UDP_Send_Error(errno)
 	}
-	bytes_written = int(res)
-	return
+	return int(bytes_written), nil
 }
 
 @(private)
-_shutdown :: proc(skt: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {
-	s := any_socket_to_socket(skt)
-	res := os.shutdown(os.Socket(s), int(manner))
-	if res != os.ERROR_NONE {
-		return Shutdown_Error(res)
+_shutdown :: proc(sock: Any_Socket, manner: Shutdown_Manner) -> (err: Network_Error) {
+	os_sock := _unwrap_os_socket(sock)
+	errno := linux.shutdown(os_sock, cast(linux.Shutdown_How) manner)
+	if errno != .NONE {
+		return Shutdown_Error(errno)
 	}
-	return
+	return nil
 }
 
+// TODO(flysand): Figure out what we want to do with this on core:sys/ level.
 @(private)
-_set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error {
-	level := os.SOL_SOCKET if option != .TCP_Nodelay else os.IPPROTO_TCP
-
+_set_option :: proc(sock: Any_Socket, option: Socket_Option, value: any, loc := #caller_location) -> Network_Error {
+	level: int
+	if option == .TCP_Nodelay {
+		level = int(linux.SOL_TCP)
+	} else {
+		level = int(linux.SOL_SOCKET)
+	}
+	os_sock := _unwrap_os_socket(sock)
 	// NOTE(tetra, 2022-02-15): On Linux, you cannot merely give a single byte for a bool;
 	//  it _has_ to be a b32.
-	//  I haven't tested if you can give more than that.
+	//  I haven't tested if you can give more than that. <-- (flysand) probably not, posix explicitly specifies an int
 	bool_value: b32
 	int_value: i32
-	timeval_value: os.Timeval
-
-	ptr: rawptr
-	len: os.socklen_t
-
+	timeval_value: linux.Time_Val
+	errno: linux.Errno
 	switch option {
 	case
 		.Reuse_Address,
@@ -258,7 +311,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 		.Out_Of_Bounds_Data_Inline,
 		.TCP_Nodelay:
 		// TODO: verify whether these are options or not on Linux
-		// .Broadcast,
+		// .Broadcast, <-- yes
 		// .Conditional_Accept,
 		// .Dont_Linger:
 			switch x in value {
@@ -274,8 +327,7 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 			case:
 				panic("set_option() value must be a boolean here", loc)
 			}
-			ptr = &bool_value
-			len = size_of(bool_value)
+			errno = linux.setsockopt(os_sock, level, int(option), &bool_value)
 	case
 		.Linger,
 		.Send_Timeout,
@@ -283,125 +335,49 @@ _set_option :: proc(s: Any_Socket, option: Socket_Option, value: any, loc := #ca
 			t, ok := value.(time.Duration)
 			if !ok do panic("set_option() value must be a time.Duration here", loc)
 
-			micros := i64(time.duration_microseconds(t))
-			timeval_value.microseconds = int(micros % 1e6)
-			timeval_value.seconds = (micros - i64(timeval_value.microseconds)) / 1e6
-
-			ptr = &timeval_value
-			len = size_of(timeval_value)
+			micros := cast(i64) (time.duration_microseconds(t))
+			timeval_value.microseconds = cast(int) (micros % 1e6)
+			timeval_value.seconds = cast(int) ((micros - i64(timeval_value.microseconds)) / 1e6)
+			errno = linux.setsockopt(os_sock, level, int(option), &timeval_value)
 	case
 		.Receive_Buffer_Size,
 		.Send_Buffer_Size:
 			// TODO: check for out of range values and return .Value_Out_Of_Range?
 			switch i in value {
-			case   i8,   u8: i2 := i; int_value = os.socklen_t((^u8)(&i2)^)
-			case  i16,  u16: i2 := i; int_value = os.socklen_t((^u16)(&i2)^)
-			case  i32,  u32: i2 := i; int_value = os.socklen_t((^u32)(&i2)^)
-			case  i64,  u64: i2 := i; int_value = os.socklen_t((^u64)(&i2)^)
-			case i128, u128: i2 := i; int_value = os.socklen_t((^u128)(&i2)^)
-			case  int, uint: i2 := i; int_value = os.socklen_t((^uint)(&i2)^)
+			case   i8,   u8: i2 := i; int_value = i32((^u8)(&i2)^)
+			case  i16,  u16: i2 := i; int_value = i32((^u16)(&i2)^)
+			case  i32,  u32: i2 := i; int_value = i32((^u32)(&i2)^)
+			case  i64,  u64: i2 := i; int_value = i32((^u64)(&i2)^)
+			case i128, u128: i2 := i; int_value = i32((^u128)(&i2)^)
+			case  int, uint: i2 := i; int_value = i32((^uint)(&i2)^)
 			case:
 				panic("set_option() value must be an integer here", loc)
 			}
-			ptr = &int_value
-			len = size_of(int_value)
+			errno = linux.setsockopt(os_sock, level, int(option), &int_value)
 	}
-
-	skt := any_socket_to_socket(s)
-	res := os.setsockopt(os.Socket(skt), int(level), int(option), ptr, len)
-	if res != os.ERROR_NONE {
-		return Socket_Option_Error(res)
+	if errno != .NONE {
+		return Socket_Option_Error(errno)
 	}
-
 	return nil
 }
 
 @(private)
-_set_blocking :: proc(socket: Any_Socket, should_block: bool) -> (err: Network_Error) {
-	socket := any_socket_to_socket(socket)
-
-	flags, getfl_err := os.fcntl(int(socket), os.F_GETFL, 0)
-	if getfl_err != os.ERROR_NONE {
-		return Set_Blocking_Error(getfl_err)
+_set_blocking :: proc(sock: Any_Socket, should_block: bool) -> (err: Network_Error) {
+	errno: linux.Errno
+	flags: linux.Open_Flags
+	os_sock := _unwrap_os_socket(sock)
+	flags, errno = linux.fcntl(os_sock, linux.F_GETFL)
+	if errno != .NONE {
+		return Set_Blocking_Error(errno)
 	}
-
 	if should_block {
-		flags &= ~int(os.O_NONBLOCK)
+		flags &= ~{.NONBLOCK}
 	} else {
-		flags |= int(os.O_NONBLOCK)
+		flags |= {.NONBLOCK}
 	}
-
-	_, setfl_err := os.fcntl(int(socket), os.F_SETFL, flags)
-	if setfl_err != os.ERROR_NONE {
-		return Set_Blocking_Error(setfl_err)
+	errno = linux.fcntl(os_sock, linux.F_SETFL, flags)
+	if errno != .NONE {
+		return Set_Blocking_Error(errno)
 	}
-
 	return nil
 }
-
-@(private)
-_endpoint_to_sockaddr :: proc(ep: Endpoint) -> (sockaddr: os.SOCKADDR_STORAGE_LH) {
-	switch a in ep.address {
-	case IP4_Address:
-		(^os.sockaddr_in)(&sockaddr)^ = os.sockaddr_in {
-			sin_port = u16be(ep.port),
-			sin_addr = transmute(os.in_addr) a,
-			sin_family = u16(os.AF_INET),
-		}
-		return
-	case IP6_Address:
-		(^os.sockaddr_in6)(&sockaddr)^ = os.sockaddr_in6 {
-			sin6_port = u16be(ep.port),
-			sin6_addr = transmute(os.in6_addr) a,
-			sin6_family = u16(os.AF_INET6),
-		}
-		return
-	}
-	unreachable()
-}
-
-@(private)
-_sockaddr_storage_to_endpoint :: proc(native_addr: ^os.SOCKADDR_STORAGE_LH) -> (ep: Endpoint) {
-	switch native_addr.ss_family {
-	case u16(os.AF_INET):
-		addr := cast(^os.sockaddr_in) native_addr
-		port := int(addr.sin_port)
-		ep = Endpoint {
-			address = IP4_Address(transmute([4]byte) addr.sin_addr),
-			port = port,
-		}
-	case u16(os.AF_INET6):
-		addr := cast(^os.sockaddr_in6) native_addr
-		port := int(addr.sin6_port)
-		ep = Endpoint {
-			address = IP6_Address(transmute([8]u16be) addr.sin6_addr),
-			port = port,
-		}
-	case:
-		panic("native_addr is neither IP4 or IP6 address")
-	}
-	return
-}
-
-@(private)
-_sockaddr_basic_to_endpoint :: proc(native_addr: ^os.SOCKADDR) -> (ep: Endpoint) {
-	switch native_addr.sa_family {
-	case u16(os.AF_INET):
-		addr := cast(^os.sockaddr_in) native_addr
-		port := int(addr.sin_port)
-		ep = Endpoint {
-			address = IP4_Address(transmute([4]byte) addr.sin_addr),
-			port = port,
-		}
-	case u16(os.AF_INET6):
-		addr := cast(^os.sockaddr_in6) native_addr
-		port := int(addr.sin6_port)
-		ep = Endpoint {
-			address = IP6_Address(transmute([8]u16be) addr.sin6_addr),
-			port = port,
-		}
-	case:
-		panic("native_addr is neither IP4 or IP6 address")
-	}
-	return
-}

+ 12 - 1
core/os/os_linux.odin

@@ -8,7 +8,18 @@ import "core:strings"
 import "core:c"
 import "core:strconv"
 import "core:intrinsics"
-import "core:sys/unix"
+
+// NOTE(flysand): For compatibility we'll make core:os package
+// depend on the old (scheduled for removal) linux package.
+// Seeing that there are plans for os2, I'm imagining that *that*
+// package should inherit the new sys functionality.
+// The reasons for these are as follows:
+//  1. It's very hard to update this package without breaking *a lot* of code.
+//  2. os2 is not stable anyways, so we can break compatibility all we want
+// It might be weird to bring up compatibility when Odin in it's nature isn't
+// all that about compatibility. But we don't want to push experimental changes
+// and have people's code break while it's still work in progress.
+import unix "core:sys/unix"
 
 Handle    :: distinct i32
 Pid       :: distinct i32

+ 32 - 67
core/sync/futex_linux.odin

@@ -2,95 +2,60 @@
 //+build linux
 package sync
 
-import "core:c"
 import "core:time"
-import "core:intrinsics"
-import "core:sys/unix"
+import "core:sys/linux"
 
-FUTEX_WAIT :: 0
-FUTEX_WAKE :: 1
-FUTEX_PRIVATE_FLAG :: 128
-
-FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
-FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
-
-ESUCCESS  :: 0
-EINTR     :: -4
-EAGAIN    :: -11
-EFAULT    :: -14
-EINVAL    :: -22
-ETIMEDOUT :: -110
-
-get_errno :: proc "contextless" (r: int) -> int {
-	if -4096 < r && r < 0 {
-		return r
-	}
-	return 0
-}
-
-internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
-	code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
-	return get_errno(code)
-}
-
-
-_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
-	err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
-	switch err {
-	case ESUCCESS, EINTR, EAGAIN, EINVAL:
-		// okay
-	case ETIMEDOUT:
+_futex_wait :: proc "contextless" (futex: ^Futex, expected: u32) -> bool {
+	errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAIT, {.PRIVATE}, expected)
+	if errno == .ETIMEDOUT {
 		return false
-	case EFAULT: 
-		fallthrough
+	}
+	#partial switch errno {
+	case .NONE, .EINTR, .EAGAIN:
+		return true
 	case:
+		// TODO(flysand): More descriptive panic messages based on the vlaue of `errno`
 		_panic("futex_wait failure")
 	}
-	return true
 }
 
-_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
+_futex_wait_with_timeout :: proc "contextless" (futex: ^Futex, expected: u32, duration: time.Duration) -> bool {
 	if duration <= 0 {
 		return false
 	}
-	
-	timespec_t :: struct {
-		tv_sec:  c.long,
-		tv_nsec: c.long,
-	}
-	
-	err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, &timespec_t{
-		tv_sec  = (c.long)(duration/1e9),
-		tv_nsec = (c.long)(duration%1e9),
+	errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAIT, {.PRIVATE}, expected, &linux.Time_Spec{
+		time_sec  = cast(uint)(duration/1e9),
+		time_nsec = cast(uint)(duration%1e9),
 	})
-	switch err {
-	case ESUCCESS, EINTR, EAGAIN, EINVAL:
-		// okay
-	case ETIMEDOUT:
+	if errno == .ETIMEDOUT {
 		return false
-	case EFAULT: 
-		fallthrough
+	}
+	#partial switch errno {
+	case .NONE, .EINTR, .EAGAIN:
+		return true
 	case:
 		_panic("futex_wait_with_timeout failure")
 	}
-	return true
 }
 
-
-_futex_signal :: proc "contextless" (f: ^Futex) {
-	err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
-	switch err {
-	case ESUCCESS, EINVAL, EFAULT:
-		// okay
+_futex_signal :: proc "contextless" (futex: ^Futex) {
+	_, errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAKE, {.PRIVATE}, 1)
+	#partial switch errno {
+	case .NONE:
+		return
 	case:
 		_panic("futex_wake_single failure")
 	}
 }
-_futex_broadcast :: proc "contextless" (f: ^Futex)  {
-	err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
-	switch err {
-	case ESUCCESS, EINVAL, EFAULT:
-		// okay
+
+_futex_broadcast :: proc "contextless" (futex: ^Futex)  {
+	// NOTE(flysand): This code was kinda funny and I don't want to remove it, but here I will
+	// record history of what has been in here before
+	//     FUTEX_WAKE_PRIVATE | FUTEX_WAKE
+	_, errno := linux.futex(cast(^linux.Futex) futex, linux.FUTEX_WAKE, {.PRIVATE}, max(i32))
+	#partial switch errno {
+	case .NONE:
+		return
 	case:
 		_panic("_futex_wake_all failure")
 	}

+ 2 - 2
core/sync/primitives_linux.odin

@@ -2,8 +2,8 @@
 //+private
 package sync
 
-import "core:sys/unix"
+import "core:sys/linux"
 
 _current_thread_id :: proc "contextless" () -> int {
-	return unix.sys_gettid()
+	return cast(int) linux.gettid()
 }

+ 23 - 75
core/sys/info/platform_linux.odin

@@ -1,40 +1,34 @@
 // +build linux
 package sysinfo
 
-import "core:c"
-import sys "core:sys/unix"
 import "core:intrinsics"
 import "core:runtime"
-import "core:os"
 import "core:strings"
 import "core:strconv"
 
+import "core:sys/linux"
+
 @(private)
 version_string_buf: [1024]u8
 
 @(init, private)
 init_os_version :: proc () {
 	os_version.platform = .Linux
-
 	// Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
-	fd, err := os.open("/etc/os-release", os.O_RDONLY, 0)
-	if err != 0 {
-		return
+	fd, errno := linux.open("/etc/os-release", {.RDONLY}, {})
+	assert(errno == .NONE, "Failed to read /etc/os-release")
+	defer {
+		errno := linux.close(fd)
+		assert(errno == .NONE, "Failed to close the file descriptor")
 	}
-	defer os.close(fd)
-
 	os_release_buf: [2048]u8
-	n, read_err := os.read(fd, os_release_buf[:])
-	if read_err != 0 {
-		return
-	}
+	n, read_errno := linux.read(fd, os_release_buf[:])
+	assert(read_errno == .NONE, "Failed to read data from /etc/os-release")
 	release := string(os_release_buf[:n])
-
+	// Search the line in the file until we find "PRETTY_NAME="
 	NEEDLE :: "PRETTY_NAME=\""
 	pretty_start := strings.index(release, NEEDLE)
-
 	b := strings.builder_from_bytes(version_string_buf[:])
-
 	if pretty_start > 0 {
 		for r, i in release[pretty_start + len(NEEDLE):] {
 			if r == '"' {
@@ -46,94 +40,48 @@ init_os_version :: proc () {
 			}
 		}
 	}
-
-	NEW_UTS_LEN :: 64
-	UTS_Name :: struct {
-		sys_name:    [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-		node_name:   [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-		release:     [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-		version:     [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-		machine:     [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-		domain_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
-	}
-	uts: UTS_Name
-
 	// Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
-	if intrinsics.syscall(sys.SYS_uname, uintptr(&uts)) != 0 {
-		return
-	}
-
+	uts: linux.UTS_Name
+	uname_errno := linux.uname(&uts)
+	assert(uname_errno == .NONE, "This should never happen!")
+	// Append the system name (typically "Linux") and kernel release (looks like 6.5.2-arch1-1)
 	strings.write_string(&b, ", ")
-	strings.write_string(&b, string(cstring(&uts.sys_name[0])))
+	strings.write_string(&b, string(cstring(&uts.sysname[0])))
 	strings.write_rune(&b, ' ')
-
 	l := strings.builder_len(b)
 	strings.write_string(&b, string(cstring(&uts.release[0])))
-
-	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
-
 	// Parse kernel version, as substrings of the version info in `version_string_buf`
+	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
 	if len(version_bits) > 1 {
 		os_version.version = version_bits[1]
 	}
-
 	// Parse major, minor, patch from release info
 	triplet := strings.split(version_bits[0], ".", context.temp_allocator)
 	if len(triplet) == 3 {
 		major, major_ok := strconv.parse_int(triplet[0])
 		minor, minor_ok := strconv.parse_int(triplet[1])
 		patch, patch_ok := strconv.parse_int(triplet[2])
-
 		if major_ok && minor_ok && patch_ok {
 			os_version.major = major
 			os_version.minor = minor
 			os_version.patch = patch
 		}
 	}
-
 	// Finish the string
 	os_version.as_string = strings.to_string(b)
 }
 
-Sys_Info :: struct {
-	uptime:    c.long,     // Seconds since boot
-	loads:     [3]c.long,  // 1, 5, 15 minute load averages
-	totalram:  c.ulong,    // Total usable main memory size
-	freeram:   c.ulong,    // Available memory size
-	sharedram: c.ulong,    // Amount of shared memory
-	bufferram: c.ulong,    // Memory used by buffers
-	totalswap: c.ulong,    // Total swap space size
-	freeswap:  c.ulong,    // Swap space still available
-	procs:     c.ushort,   // Number of current processes
-	totalhigh: c.ulong,    // Total high memory size
-	freehigh:  c.ulong,    // Available high memory size
-	mem_unit:  c.int,      // Memory unit size in bytes
-	_padding:  [20 - (2 * size_of(c.long)) - size_of(c.int)]u8,
-}
-
-get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) {
-	si: Sys_Info
-	err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si)))
-	if err != 0 {
-		// Unable to retrieve sysinfo
-		return {}, false
-	}
-	return si, true
-}
-
 @(init)
 init_ram :: proc() {
 	// Retrieve RAM info using `sysinfo`
-	si, ok := get_sysinfo()
-	if !ok {
-		return
-	}
-
+	sys_info: linux.Sys_Info
+	errno := linux.sysinfo(&sys_info)
+	assert(errno == .NONE, "Good luck to whoever's debugging this, something's seriously cucked up!")
 	ram = RAM{
-		total_ram  = int(si.totalram)  * int(si.mem_unit),
-		free_ram   = int(si.freeram)   * int(si.mem_unit),
-		total_swap = int(si.totalswap) * int(si.mem_unit),
-		free_swap  = int(si.freeswap)  * int(si.mem_unit),
+		total_ram  = int(sys_info.totalram)  * int(sys_info.mem_unit),
+		free_ram   = int(sys_info.freeram)   * int(sys_info.mem_unit),
+		total_swap = int(sys_info.totalswap) * int(sys_info.mem_unit),
+		free_swap  = int(sys_info.freeswap)  * int(sys_info.mem_unit),
 	}
 }

+ 1400 - 0
core/sys/linux/bits.odin

@@ -0,0 +1,1400 @@
+package linux
+
+
+/// Represents an error returned by most of syscalls
+Errno :: enum i32 {
+    NONE = 0,
+    // Errno-base
+    EPERM           = 1,
+    ENOENT          = 2,
+    ESRCH           = 3,
+    EINTR           = 4,
+    EIO             = 5,
+    ENXIO           = 6,
+    E2BIG           = 7,
+    ENOEXEC         = 8,
+    EBADF           = 9,
+    ECHILD          = 10,
+    EAGAIN          = 11,
+    ENOMEM          = 12,
+    EACCES          = 13,
+    EFAULT          = 14,
+    ENOTBLK         = 15,
+    EBUSY           = 16,
+    EEXIST          = 17,
+    EXDEV           = 18,
+    ENODEV          = 19,
+    ENOTDIR         = 20,
+    EISDIR          = 21,
+    EINVAL          = 22,
+    ENFILE          = 23,
+    EMFILE          = 24,
+    ENOTTY          = 25,
+    ETXTBSY         = 26,
+    EFBIG           = 27,
+    ENOSPC          = 28,
+    ESPIPE          = 29,
+    EROFS           = 30,
+    EMLINK          = 31,
+    EPIPE           = 32,
+    EDOM            = 33,
+    ERANGE          = 34,
+    // Linux
+    EDEADLK         = 35,
+    ENAMETOOLONG    = 36,
+    ENOLCK          = 37,
+    ENOSYS          = 38,
+    ENOTEMPTY       = 39,
+    ELOOP           = 40,
+    ENOMSG          = 42,
+    EIDRM           = 43,
+    ECHRNG          = 44,
+    EL2NSYNC        = 45,
+    EL3HLT          = 46,
+    EL3RST          = 47,
+    ELNRNG          = 48,
+    EUNATCH         = 49,
+    ENOCSI          = 50,
+    EL2HLT          = 51,
+    EBADE           = 52,
+    EBADR           = 53,
+    EXFULL          = 54,
+    ENOANO          = 55,
+    EBADRQC         = 56,
+    EBADSLT         = 57,
+    EBFONT          = 59,
+    ENOSTR          = 60,
+    ENODATA         = 61,
+    ETIME           = 62,
+    ENOSR           = 63,
+    ENONET          = 64,
+    ENOPKG          = 65,
+    EREMOTE         = 66,
+    ENOLINK         = 67,
+    EADV            = 68,
+    ESRMNT          = 69,
+    ECOMM           = 70,
+    EPROTO          = 71,
+    EMULTIHOP       = 72,
+    EDOTDOT         = 73,
+    EBADMSG         = 74,
+    EOVERFLOW       = 75,
+    ENOTUNIQ        = 76,
+    EBADFD          = 77,
+    EREMCHG         = 78,
+    ELIBACC         = 79,
+    ELIBBAD         = 80,
+    ELIBSCN         = 81,
+    ELIBMAX         = 82,
+    ELIBEXEC        = 83,
+    EILSEQ          = 84,
+    ERESTART        = 85,
+    ESTRPIPE        = 86,
+    EUSERS          = 87,
+    ENOTSOCK        = 88,
+    EDESTADDRREQ    = 89,
+    EMSGSIZE        = 90,
+    EPROTOTYPE      = 91,
+    ENOPROTOOPT     = 92,
+    EPROTONOSUPPORT = 93,
+    ESOCKTNOSUPPORT = 94,
+    EOPNOTSUPP      = 95,
+    EPFNOSUPPORT    = 96,
+    EAFNOSUPPORT    = 97,
+    EADDRINUSE      = 98,
+    EADDRNOTAVAIL   = 99,
+    ENETDOWN        = 100,
+    ENETUNREACH     = 101,
+    ENETRESET       = 102,
+    ECONNABORTED    = 103,
+    ECONNRESET      = 104,
+    ENOBUFS         = 105,
+    EISCONN         = 106,
+    ENOTCONN        = 107,
+    ESHUTDOWN       = 108,
+    ETOOMANYREFS    = 109,
+    ETIMEDOUT       = 110,
+    ECONNREFUSED    = 111,
+    EHOSTDOWN       = 112,
+    EHOSTUNREACH    = 113,
+    EALREADY        = 114,
+    EINPROGRESS     = 115,
+    ESTALE          = 116,
+    EUCLEAN         = 117,
+    ENOTNAM         = 118,
+    ENAVAIL         = 119,
+    EISNAM          = 120,
+    EREMOTEIO       = 121,
+    EDQUOT          = 122,
+    ENOMEDIUM       = 123,
+    EMEDIUMTYPE     = 124,
+    ECANCELED       = 125,
+    ENOKEY          = 126,
+    EKEYEXPIRED     = 127,
+    EKEYREVOKED     = 128,
+    EKEYREJECTED    = 129,
+    EOWNERDEAD      = 130,
+    ENOTRECOVERABLE = 131,
+    ERFKILL         = 132,
+    EHWPOISON       = 133,
+    // Errno aliases
+    EWOULDBLOCK     = EAGAIN,
+    EDEADLOCK       = EDEADLK,
+}
+
+
+/// Bits for Open_Flags
+Open_Flags_Bits :: enum {
+    RDONLY    = 0,
+    WRONLY    = 1,
+    RDWR      = 2,
+    CREAT     = 6,
+    EXCL      = 7,
+    NOCTTY    = 8,
+    TRUNC     = 9,
+    APPEND    = 10,
+    NONBLOCK  = 11,
+    DSYNC     = 12,
+    ASYNC     = 13,
+    DIRECT    = 14,
+    DIRECTORY = 16,
+    NOFOLLOW  = 17,
+    NOATIME   = 18,
+    CLOEXEC   = 19,
+    PATH      = 21,
+}
+
+/// Bits for FD_Flags bitset
+FD_Flags_Bits :: enum {
+    SYMLINK_NOFOLLOW   = 8,
+    REMOVEDIR          = 9,
+    EACCESS            = 9,
+    SYMLINK_FOLLOW     = 10,
+    NO_AUTOMOUNT       = 11,
+    EMPTY_PATH         = 12,
+    STATX_FORCE_SYNC   = 13,
+    STATX_DONT_SYNC    = 14,
+    RECURSIVE          = 15,
+}
+
+/// The bits for the Mode bitset.
+Mode_Bits :: enum {
+    IXOTH  = 0,  // 0o0000001
+    IWOTH  = 1,  // 0o0000002
+    IROTH  = 2,  // 0o0000004
+    IXGRP  = 3,  // 0o0000010
+    IWGRP  = 4,  // 0o0000020
+    IRGRP  = 5,  // 0o0000040
+    IXUSR  = 6,  // 0o0000100
+    IWUSR  = 7,  // 0o0000200
+    IRUSR  = 8,  // 0o0000400
+    ISVTX  = 9,  // 0o0001000
+    ISGID  = 10, // 0o0002000
+    ISUID  = 11, // 0o0004000
+    IFFIFO = 12, // 0o0010000
+    IFCHR  = 13, // 0o0020000
+    IFDIR  = 14, // 0o0040000
+    IFREG  = 15, // 0o0100000
+}
+
+/// The bits used by the Statx_Mask bitset
+Statx_Mask_Bits :: enum {
+    TYPE         = 0,
+    MODE         = 1,
+    NLINK        = 2,
+    UID          = 3,
+    GID          = 4,
+    ATIME        = 5,
+    MTIME        = 6,
+    CTIME        = 7,
+    INO          = 8,
+    SIZE         = 9,
+    BLOCKS       = 10,
+    BTIME        = 11,
+    MNT_ID       = 12,
+    DIOALIGN     = 13,
+}
+
+/// Bits found in Statx_Attr bitset
+/// You should not use these directly
+Statx_Attr_Bits :: enum {
+    COMPRESSED = 2,  // 0x00000004
+    IMMUTABLE  = 4,  // 0x00000010
+    APPEND     = 5,  // 0x00000020
+    NODUMP     = 6,  // 0x00000040
+    ENCRYPTED  = 11, // 0x00000800
+    AUTOMOUNT  = 12, // 0x00001000
+    MOUNT_ROOT = 13, // 0x00002000
+    VERITY     = 20, // 0x00100000
+    DAX        = 21, // 0x00200000
+}
+
+/// Magic bits for filesystems returned by Stat_FS
+FS_Magic :: enum u32 {
+    ADFS_SUPER_MAGIC      = 0xadf5,
+    AFFS_SUPER_MAGIC      = 0xadff,
+    AFS_SUPER_MAGIC       = 0x5346414f,
+    ANON_INODE_FS_MAGIC   = 0x09041934,
+    AUTOFS_SUPER_MAGIC    = 0x0187,
+    BDEVFS_MAGIC          = 0x62646576,
+    BEFS_SUPER_MAGIC      = 0x42465331,
+    BFS_MAGIC             = 0x1badface,
+    BINFMTFS_MAGIC        = 0x42494e4d,
+    BPF_FS_MAGIC          = 0xcafe4a11,
+    BTRFS_SUPER_MAGIC     = 0x9123683e,
+    BTRFS_TEST_MAGIC      = 0x73727279,
+    CGROUP_SUPER_MAGIC    = 0x27e0eb,
+    CGROUP2_SUPER_MAGIC   = 0x63677270,
+    CIFS_MAGIC_NUMBER     = 0xff534d42,
+    CODA_SUPER_MAGIC      = 0x73757245,
+    COH_SUPER_MAGIC       = 0x012ff7b7,
+    CRAMFS_MAGIC          = 0x28cd3d45,
+    DEBUGFS_MAGIC         = 0x64626720,
+    DEVFS_SUPER_MAGIC     = 0x1373,
+    DEVPTS_SUPER_MAGIC    = 0x1cd1,
+    ECRYPTFS_SUPER_MAGIC  = 0xf15f,
+    EFIVARFS_MAGIC        = 0xde5e81e4,
+    EFS_SUPER_MAGIC       = 0x00414a53,
+    EXT_SUPER_MAGIC       = 0x137d,
+    EXT2_OLD_SUPER_MAGIC  = 0xef51,
+    EXT2_SUPER_MAGIC      = 0xef53,
+    EXT3_SUPER_MAGIC      = 0xef53,
+    EXT4_SUPER_MAGIC      = 0xef53,
+    F2FS_SUPER_MAGIC      = 0xf2f52010,
+    FUSE_SUPER_MAGIC      = 0x65735546,
+    FUTEXFS_SUPER_MAGIC   = 0xbad1dea,
+    HFS_SUPER_MAGIC       = 0x4244,
+    HOSTFS_SUPER_MAGIC    = 0x00c0ffee,
+    HPFS_SUPER_MAGIC      = 0xf995e849,
+    HUGETLBFS_MAGIC       = 0x958458f6,
+    ISOFS_SUPER_MAGIC     = 0x9660,
+    JFFS2_SUPER_MAGIC     = 0x72b6,
+    JFS_SUPER_MAGIC       = 0x3153464a,
+    MINIX_SUPER_MAGIC     = 0x137f,
+    MINIX_SUPER_MAGIC2    = 0x138f,
+    MINIX2_SUPER_MAGIC    = 0x2468,
+    MINIX2_SUPER_MAGIC2   = 0x2478,
+    MINIX3_SUPER_MAGIC    = 0x4d5a,
+    MQUEUE_MAGIC          = 0x19800202,
+    MSDOS_SUPER_MAGIC     = 0x4d44,
+    MTD_INODE_FS_MAGIC    = 0x11307854,
+    NCP_SUPER_MAGIC       = 0x564c,
+    NFS_SUPER_MAGIC       = 0x6969,
+    NILFS_SUPER_MAGIC     = 0x3434,
+    NSFS_MAGIC            = 0x6e736673,
+    NTFS_SB_MAGIC         = 0x5346544e,
+    OCFS2_SUPER_MAGIC     = 0x7461636f,
+    OPENPROM_SUPER_MAGIC  = 0x9fa1,
+    OVERLAYFS_SUPER_MAGIC = 0x794c7630,
+    PIPEFS_MAGIC          = 0x50495045,
+    PROC_SUPER_MAGIC      = 0x9fa0,
+    PSTOREFS_MAGIC        = 0x6165676c,
+    QNX4_SUPER_MAGIC      = 0x002f,
+    QNX6_SUPER_MAGIC      = 0x68191122,
+    RAMFS_MAGIC           = 0x858458f6,
+    REISERFS_SUPER_MAGIC  = 0x52654973,
+    ROMFS_MAGIC           = 0x7275,
+    SECURITYFS_MAGIC      = 0x73636673,
+    SELINUX_MAGIC         = 0xf97cff8c,
+    SMACK_MAGIC           = 0x43415d53,
+    SMB_SUPER_MAGIC       = 0x517b,
+    SMB2_MAGIC_NUMBER     = 0xfe534d42,
+    SOCKFS_MAGIC          = 0x534f434b,
+    SQUASHFS_MAGIC        = 0x73717368,
+    SYSFS_MAGIC           = 0x62656572,
+    SYSV2_SUPER_MAGIC     = 0x012ff7b6,
+    SYSV4_SUPER_MAGIC     = 0x012ff7b5,
+    TMPFS_MAGIC           = 0x01021994,
+    TRACEFS_MAGIC         = 0x74726163,
+    UDF_SUPER_MAGIC       = 0x15013346,
+    UFS_MAGIC             = 0x00011954,
+    USBDEVICE_SUPER_MAGIC = 0x9fa2,
+    V9FS_MAGIC            = 0x01021997,
+    VXFS_SUPER_MAGIC      = 0xa501fcf5,
+    XENFS_SUPER_MAGIC     = 0xabba1974,
+    XENIX_SUPER_MAGIC     = 0x012ff7b4,
+    XFS_SUPER_MAGIC       = 0x58465342,
+    _XIAFS_SUPER_MAGIC    = 0x012fd16d,
+}
+
+/// Bits for FS_Flags bitset
+FS_Flags_Bits :: enum {
+    RDONLY       = 0,
+    NOSUID       = 1,
+    NODEV        = 2,
+    NOEXEC       = 3,
+    SYNCHRONOUS  = 4,
+    VALID        = 5,
+    MANDLOCK     = 6,
+    NOATIME      = 10,
+    NODIRATIME   = 11,
+    RELATIME     = 12,
+    NOSYMFOLLOW  = 13,
+}
+
+Seek_Whence :: enum i16 {
+    SET  = 0,
+    CUR  = 1,
+    END  = 2,
+    DATA = 3,
+    HOLE = 4,
+}
+
+/// Bits for Close_Range_Flags
+Close_Range_Flags_Bits :: enum {
+    CLOEXEC = 2,
+    UNSHARE = 1,
+}
+
+/// Bits for Rename_Flags
+Rename_Flags_Bits :: enum {
+    EXCHANGE  = 1,
+    NOREPLACE = 0,
+    WHITEOUT  = 2,
+}
+
+/// Type of the file in a directory entry
+Dirent_Type :: enum u8 {
+    UNKNOWN = 0,
+    FIFO    = 1,
+    CHR     = 2,
+    DIR     = 4,
+    BLK     = 6,
+    REG     = 8,
+    LNK     = 10,
+    SOCK    = 12,
+    WHT     = 14,
+}
+
+/// Type of a lock for fcntl.2
+FLock_Type :: enum i16 {
+    RDLCK = 0,
+    WRLCK = 1,
+    UNLCK = 2,
+}
+
+/// Bits for FD_Notifications
+FD_Notifications_Bits :: enum {
+    ACCESS    = 0,
+    MODIFY    = 1,
+    CREATE    = 2,
+    DELETE    = 3,
+    RENAME    = 4,
+    ATTRIB    = 5,
+    MULTISHOT = 31,
+}
+
+/// Bits for seal
+Seal_Bits :: enum {
+    SEAL         = 0,
+    SHRINK       = 1,
+    GROW         = 2,
+    WRITE        = 3,
+    FUTURE_WRITE = 4,
+}
+
+RW_Hint :: enum u64  {
+    WRITE_LIFE_NOT_SET = 0,
+    WRITE_LIFE_NONE    = 1,
+    WRITE_LIFE_SHORT   = 2,
+    WRITE_LIFE_MEDIUM  = 3,
+    WRITE_LIFE_LONG    = 4,
+    WRITE_LIFE_EXTREME = 5,
+}
+
+FD_Lease :: enum {
+    RDLCK = 0,
+    WRLCK = 1,
+    UNLCK = 2,
+}
+
+/// Kind of owner for FD_Owner
+F_Owner_Type :: enum i32 {
+    OWNER_TID  = 0,
+    OWNER_PID  = 1,
+    OWNER_PGRP = 2,
+}
+
+/// Command for fcntl.2
+FCntl_Command :: enum {
+    DUPFD             = 0,
+    GETFD             = 1,
+    SETFD             = 2,
+    GETFL             = 3,
+    SETFL             = 4,
+    GETLK             = 5,
+    SETLK             = 6,
+    SETLKW            = 7,
+    SETOWN            = 8,
+    GETOWN            = 9,
+    SETSIG            = 10,
+    GETSIG            = 11,
+    SETOWN_EX         = 15,
+    GETOWN_EX         = 16,
+    // OFD_GETLK         = 36,
+    // OFD_SETLK         = 37,
+    // OFD_SETLKW        = 38,
+    SETLEASE          = 1024,
+    GETLEASE          = 1025,
+    NOTIFY            = 1026,
+    DUPFD_CLOEXEC     = 1030,
+    SETPIPE_SZ        = 1031,
+    GETPIPE_SZ        = 1032,
+    ADD_SEALS         = 1033,
+    GET_SEALS         = 1034,
+    GET_RW_HINT       = 1035,
+    SET_RW_HINT       = 1036,
+    GET_FILE_RW_HINT  = 1037,
+    SET_FILE_RW_HINT  = 1038,
+    // F_OK                = 0,
+}
+
+Fd_Poll_Events_Bits :: enum {
+    IN     = 0,
+    PRI    = 1,
+    OUT    = 2,
+    ERR    = 3,
+    HUP    = 4,
+    NVAL   = 5,
+    RDNORM = 6,
+    RDBAND = 7,
+    WRNORM = 8,
+    WRBAND = 9,
+    MSG    = 10,
+    REMOVE = 12,
+    RDHUP  = 13,
+}
+
+/// Bits for Mem_Protection bitfield
+Mem_Protection_Bits :: enum{
+    READ      = 0,
+    WRITE     = 1,
+    EXEC      = 2,
+    SEM       = 3,
+    // platform-specific section start
+    ARM64_BTI = 4,
+    ARM64_MTE = 5,
+    // platform-specific section end
+    GROWSDOWN = 24,
+    GROWSUP   = 25,
+}
+
+/// Bits for Map_Flags
+Map_Flags_Bits :: enum {
+    SHARED          = 0,
+    PRIVATE         = 1,
+    SHARED_VALIDATE = 2,
+    FIXED           = 4,
+    ANONYMOUS       = 5,
+    // platform-dependent section start
+    X86_32BIT       = 6,
+    X86_ABOVE4G     = 7,
+    // platform-dependent section end
+    GROWSDOWN       = 8,
+    DENYWRITE       = 11,
+    EXECUTABLE      = 12,
+    LOCKED          = 13,
+    NORESERVE       = 14,
+    POPULATE        = 15,
+    NONBLOCK        = 16,
+    STACK           = 17,
+    HUGETLB         = 18,
+    SYNC            = 19,
+    FIXED_NOREPLACE = 20,
+    UNINITIALIZED   = 26,
+}
+
+/// Bits for MLock_Flags
+MLock_Flags_Bits :: enum {
+    ONFAULT   = 0,
+}
+
+/// Bits for MSync_Flags
+MSync_Flags_Bits :: enum {
+    ASYNC      = 0,
+    INVALIDATE = 1,
+    SYNC       = 2,
+}
+
+/// Argument for madvice.2
+MAdvice :: enum {
+    NORMAL           = 0,
+    RANDOM           = 1,
+    SEQUENTIAL       = 2,
+    WILLNEED         = 3,
+    DONTNEED         = 4,
+    FREE             = 8,
+    REMOVE           = 9,
+    DONTFORK         = 10,
+    DOFORK           = 11,
+    MERGEABLE        = 12,
+    UNMERGEABLE      = 13,
+    HUGEPAGE         = 14,
+    NOHUGEPAGE       = 15,
+    DONTDUMP         = 16,
+    DODUMP           = 17,
+    WIPEONFORK       = 18,
+    KEEPONFORK       = 19,
+    COLD             = 20,
+    PAGEOUT          = 21,
+    POPULATE_READ    = 22,
+    POPULATE_WRITE   = 23,
+    DONTNEED_LOCKED  = 24,
+    COLLAPSE         = 25,
+    HWPOISON         = 100,
+    SOFT_OFFLINE     = 101,
+}
+
+/// Bits for PKey_Access_Rights
+PKey_Access_Bits :: enum {
+    DISABLE_ACCESS = 0,
+    DISABLE_WRITE  = 2,
+}
+
+/// Bits for MRemap_Flags
+MRemap_Flags_Bits :: enum {
+    MAYMOVE   = 0,
+    FIXED     = 1,
+    DONTUNMAP = 2,
+}
+
+/// Bits for Get_Random_Flags
+Get_Random_Flags_Bits :: enum {
+    RANDOM   = 0,
+    NONBLOCK = 1,
+    INSECURE = 2,
+}
+
+/// Bits for Perf_Flags
+Perf_Flags_Bits :: enum {
+    FD_NO_GROUP = 0,
+    FD_OUTPUT   = 1,
+    PID_CGROUP  = 2,
+    FD_CLOEXEC  = 3,
+}
+
+///  Union tag for Perf_Event_Attr struct
+Perf_Event_Type :: enum u32 {
+    HARDWARE   = 0,
+    SOFTWARE   = 1,
+    TRACEPOINT = 2,
+    HW_CACHE   = 3,
+    RAW        = 4,
+    BREAKPOINT = 5,
+}
+
+Perf_Event_Flags_Bits :: enum u64 {
+    Disabled       = 0,
+    Inherit        = 1,
+    Pinned         = 2,
+    Exclusive      = 3,
+    Exclude_User   = 4,
+    Exclude_Kernel = 5,
+    Exclude_HV     = 6,
+    Exclude_Idle   = 7,
+    Mmap           = 8,
+    Comm           = 9,
+    Freq           = 10,
+    Inherit_Stat   = 11,
+    Enable_On_Exec = 12,
+    Task           = 13,
+    Watermark      = 14,
+    Precise_IP_0   = 15,
+    Precise_IP_1   = 16,
+    Mmap_Data      = 17,
+    Sample_Id_All  = 18,
+    Exclude_Host   = 19,
+    Exclude_Guest  = 20,
+    Exclude_Callchain_Kernel = 21,
+    Exclude_Callchain_User   = 22,
+    Mmap2          = 23,
+    Comm_Exec      = 24,
+    Use_Clockid    = 25,
+    Context_Switch = 26,
+    Write_Backward = 27,
+    Namespaces     = 28,
+    KSymbol        = 29,
+    BPF_Event      = 30,
+    Aux_Output     = 31,
+    CGroup         = 32,
+    Text_Poke      = 33,
+    Build_Id       = 34,
+    Inherit_Thread = 35,
+    Remove_On_Exec = 36,
+    Sigtrap        = 37,
+}
+
+Perf_Cap_Flags_Bits :: enum u64 {
+    Bit0               = 0,
+    Bit0_Is_Deprecated = 1,
+    User_Rdpmc         = 2,
+    User_Time          = 3,
+    User_Time_Zero     = 4,
+    User_Time_Short    = 5,
+}
+
+/// Specifies the type of the hardware event that you want to get info about
+Perf_Hardware_Id :: enum u64 {
+    CPU_CYCLES              = 0,
+    INSTRUCTIONS            = 1,
+    CACHE_REFERENCES        = 2,
+    CACHE_MISSES            = 3,
+    BRANCH_INSTRUCTIONS     = 4,
+    BRANCH_MISSES           = 5,
+    BUS_CYCLES              = 6,
+    STALLED_CYCLES_FRONTEND = 7,
+    STALLED_CYCLES_BACKEND  = 8,
+    REF_CPU_CYCLES          = 9,
+}
+
+/// Specifies the cache for the particular cache event that you want to get info about
+Perf_Hardware_Cache_Id :: enum u64 {
+    L1D      = 0,
+    L1I      = 1,
+    LL       = 2,
+    DTLB     = 3,
+    ITLB     = 4,
+    BPU      = 5,
+    NODE     = 6,
+}
+
+/// Specifies the cache op that you want to get info about
+Perf_Hardware_Cache_Op_Id :: enum u64 {
+    READ     = 0,
+    WRITE    = 1,
+    PREFETCH = 2,
+}
+
+/// Specifies the cache operation result that you want to get info about
+Perf_Hardware_Cache_Result_Id :: enum u64 {
+    ACCESS   = 0,
+    MISS     = 1,
+}
+
+/// Specifies the particular software event that you want to get info about
+Perf_Software_Id :: enum u64 {
+    CPU_CLOCK         = 0,
+    TASK_CLOCK        = 1,
+    PAGE_FAULTS       = 2,
+    CONTEXT_SWITCHES  = 3,
+    CPU_MIGRATIONS    = 4,
+    PAGE_FAULTS_MIN   = 5,
+    PAGE_FAULTS_MAJ   = 6,
+    ALIGNMENT_FAULTS  = 7,
+    EMULATION_FAULTS  = 8,
+    DUMMY             = 9,
+    BPF_OUTPUT        = 10,
+    CGROUP_SWITCHES   = 11,
+
+}
+
+/// Specifies which values to include in the sample
+Perf_Event_Sample_Type_Bits :: enum {
+    IP              = 0,
+    TID             = 1,
+    TIME            = 2,
+    ADDR            = 3,
+    READ            = 4,
+    CALLCHAIN       = 5,
+    ID              = 6,
+    CPU             = 7,
+    PERIOD          = 8,
+    STREAM_ID       = 9,
+    RAW             = 10,
+    BRANCH_STACK    = 11,
+    REGS_USER       = 12,
+    STACK_USER      = 13,
+    WEIGHT          = 14,
+    DATA_SRC        = 15,
+    IDENTIFIER      = 16,
+    TRANSACTION     = 17,
+    REGS_INTR       = 18,
+    PHYS_ADDR       = 19,
+    AUX             = 20,
+    CGROUP          = 21,
+    DATA_PAGE_SIZE  = 22,
+    CODE_PAGE_SIZE  = 23,
+    WEIGHT_STRUCT   = 24,
+}
+
+/// Describes field sets to include in mmaped page
+Perf_Read_Format :: enum {
+    TOTAL_TIME_ENABLED = 0,
+    TOTAL_TIME_RUNNING = 1,
+    ID                 = 2,
+    GROUP              = 3,
+    LOST               = 4,
+}
+
+/// Chooses the breakpoint type
+Hardware_Breakpoint_Type :: enum u32 {
+    EMPTY   = 0,
+    R       = 1,
+    W       = 2,
+    X       = 4,
+    RW      = R | W,
+    INVALID = RW | X,
+}
+
+/// Bits for Branch_Sample_Type
+Branch_Sample_Type_Bits :: enum {
+    USER       = 0,
+    KERNEL     = 1,
+    HV         = 2,
+    ANY        = 3,
+    ANY_CALL   = 4,
+    ANY_RETURN = 5,
+    IND_CALL   = 6,
+    ABORT_TX   = 7,
+    IN_TX      = 8,
+    NO_TX      = 9,
+    COND       = 10,
+    CALL_STACK = 11,
+    IND_JUMP   = 12,
+    CALL       = 13,
+    NO_FLAGS   = 14,
+    NO_CYCLES  = 15,
+    TYPE_SAVE  = 16,
+    HW_INDEX   = 17,
+    PRIV_SAVE  = 18,
+}
+
+/// Represent the type of Id
+Id_Type :: enum uint {
+    ALL    = 0,
+    PID    = 1,
+    PGID   = 2,
+    PIDFD  = 3,
+}
+
+/// Options for wait syscalls
+Wait_Option :: enum {
+    WNOHANG     = 0,
+    WUNTRACED   = 1,
+    WSTOPPED    = 1,
+    WEXITED     = 2,
+    WCONTINUED  = 3,
+    WNOWAIT     = 24, 
+    // // For processes created using clone
+    __WNOTHREAD = 29,
+    __WALL      = 30,
+    __WCLONE    = 31,
+}
+
+/// Bits for flags for pidfd
+Pid_FD_Flags_Bits :: enum {
+    NONBLOCK = 11,
+}
+
+/// Priority for process, process group, user
+Priority_Which :: enum i32 {
+    PROCESS = 0,
+    PGRP    = 1,
+    USER    = 2,
+}
+
+Signal :: enum i32 {
+    // POSIX-defined signals
+    SIGINT      = 2,       // Interactive attention signal.
+    SIGILL      = 4,       // Illegal instruction.
+    SIGABRT     = 6,       // Abnormal termination.
+    SIGFPE      = 8,       // Erroneous arithmetic operation.
+    SIGSEGV     = 11,      // Invalid access to storage.
+    SIGTERM     = 15,      // Termination request.
+    // Other POSIX signals
+    SIGHUP      = 1,       // Hangup.
+    SIGQUIT     = 3,       // Quit.
+    SIGTRAP     = 5,       // Trace/breakpoint trap.
+    SIGKILL     = 9,       // Killed.
+    SIGPIPE     = 13,      // Broken pipe.
+    SIGALRM     = 14,      // Alarm clock.
+    // Adjustments needed for most linux systems
+    SIGSTKFLT   = 16,      // Stack fault (obsolete).
+    SIGPWR      = 30,      // Power failure imminent.
+    // Historical signals specified by POSIX.
+    SIGBUS      =  7,      // Bus error.
+    SIGSYS      = 31,      // Bad system call.
+    // New(er) POSIX signals (1003.1-2008, 1003.1-2013).
+    SIGURG      = 23,      // Urgent data is available at a socket.
+    SIGSTOP     = 19,      // Stop, unblockable.
+    SIGTSTP     = 20,      // Keyboard stop.
+    SIGCONT     = 18,      // Continue.
+    SIGCHLD     = 17,      // Child terminated or stopped.
+    SIGTTIN     = 21,      // Background read from control terminal.
+    SIGTTOU     = 22,      // Background write to control terminal.
+    SIGPOLL     = 29,      // Pollable event occurred (System V).
+    SIGXFSZ     = 25,      // File size limit exceeded.
+    SIGXCPU     = 24,      // CPU time limit exceeded.
+    SIGVTALRM   = 26,      // Virtual timer expired.
+    SIGPROF     = 27,      // Profiling timer expired.
+    SIGUSR1     = 10,      // User-defined signal 1.
+    SIGUSR2     = 12,      // User-defined signal 2.
+    // Nonstandard signals found in all modern POSIX systems (including both BSD and Linux).
+    SIGWINCH    = 28,      // Window size change (4.3 BSD, Sun).
+    // Archaic names for compatibility.
+    SIGIO       = SIGPOLL, // I/O now possible (4.2 BSD).
+    SIGIOT      = SIGABRT, // IOT instruction, abort() on a PDP-11.
+    SIGCLD      = SIGCHLD, // Old System V name
+}
+
+Sig_Mask_Kind :: enum i32 {
+    SIG_BLOCK   = 0,
+    SIG_UNBLOCK = 1,
+    SIG_SETMASK = 2,
+}
+
+Sig_Stack_Flag :: enum i32 {
+    DISABLE = 0,
+    ONSTACK = 1,
+    AUTODISARM = 31,
+}
+
+/// Type of socket to create
+///   For TCP you want to use SOCK_STREAM
+///   For UDP you want to use SOCK_DGRAM
+/// Also see Protocol
+Socket_Type :: enum {
+    STREAM    = 1,
+    DGRAM     = 2,
+    RAW       = 3,
+    RDM       = 4,
+    SEQPACKET = 5,
+    DCCP      = 6,
+    PACKET    = 10,
+}
+
+/// Bits for Socket_FD_Flags
+Socket_FD_Flags_Bits :: enum {
+    NONBLOCK  = 14,
+    CLOEXEC   = 25,
+}
+
+/// Protocol family
+Protocol_Family :: enum u16 {
+    UNSPEC       = 0,
+    LOCAL        = 1,
+    UNIX         = LOCAL,
+    FILE         = LOCAL,
+    INET         = 2,
+    AX25         = 3,
+    IPX          = 4,
+    APPLETALK    = 5,
+    NETROM       = 6,
+    BRIDGE       = 7,
+    ATMPVC       = 8,
+    X25          = 9,
+    INET6        = 10,
+    ROSE         = 11,
+    DECnet       = 12,
+    NETBEUI      = 13,
+    SECURITY     = 14,
+    KEY          = 15,
+    NETLINK      = 16,
+    ROUTE        = NETLINK,
+    PACKET       = 17,
+    ASH          = 18,
+    ECONET       = 19,
+    ATMSVC       = 20,
+    RDS          = 21,
+    SNA          = 22,
+    IRDA         = 23,
+    PPPOX        = 24,
+    WANPIPE      = 25,
+    LLC          = 26,
+    IB           = 27,
+    MPLS         = 28,
+    CAN          = 29,
+    TIPC         = 30,
+    BLUETOOTH    = 31,
+    IUCV         = 32,
+    RXRPC        = 33,
+    ISDN         = 34,
+    PHONET       = 35,
+    IEEE802154   = 36,
+    CAIF         = 37,
+    ALG          = 38,
+    NFC          = 39,
+    VSOCK        = 40,
+    KCM          = 41,
+    QIPCRTR      = 42,
+    SMC          = 43,
+    XDP          = 44,
+    MCTP         = 45,
+}
+
+/// The protocol number according to IANA protocol number list
+/// Full list of protocol numbers:
+///   https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
+/// Supported by the OS protocols can be queried by reading:
+///   /etc/protocols
+Protocol :: enum {
+    HOPOPT          = 0,
+    ICMP            = 1,
+    IGMP            = 2,
+    GGP             = 3,
+    IPv4            = 4,
+    ST              = 5,
+    TCP             = 6,
+    CBT             = 7,
+    EGP             = 8,
+    IGP             = 9,
+    BBN_RCC_MON     = 10,
+    NVP_II          = 11,
+    PUP             = 12,
+    EMCON           = 14,
+    XNET            = 15,
+    CHAOS           = 16,
+    UDP             = 17,
+    MUX             = 18,
+    DCN_MEAS        = 19,
+    HMP             = 20,
+    PRM             = 21,
+    XNS_IDP         = 22,
+    TRUNK_1         = 23,
+    TRUNK_2         = 24,
+    LEAF_1          = 25,
+    LEAF_2          = 26,
+    RDP             = 27,
+    IRTP            = 28,
+    ISO_TP4         = 29,
+    NETBLT          = 30,
+    MFE_NSP         = 31,
+    MERIT_INP       = 32,
+    DCCP            = 33,
+    THREE_PC        = 34,
+    IDPR            = 35,
+    XTP             = 36,
+    DDP             = 37,
+    IDPR_CMTP       = 38,
+    TP_PlusPlus     = 39,
+    IL              = 40,
+    IPv6            = 41,
+    SDRP            = 42,
+    IPv6_Route      = 43,
+    IPv6_Frag       = 44,
+    IDRP            = 45,
+    RSVP            = 46,
+    GRE             = 47,
+    DSR             = 48,
+    BNA             = 49,
+    ESP             = 50,
+    AH              = 51,
+    I_NLSP          = 52,
+    NARP            = 54,
+    MOBILE          = 55,
+    TLSP            = 56,
+    SKIP            = 57,
+    IPv6_ICMP       = 58,
+    IPv6_NoNxt      = 59,
+    IPv6_Opts       = 60,
+    CFTP            = 62,
+    SAT_EXPAK       = 64,
+    KRYPTOLAN       = 65,
+    RVD             = 66,
+    IPPC            = 67,
+    SAT_MON         = 69,
+    VISA            = 70,
+    IPCV            = 71,
+    CPNX            = 72,
+    CPHB            = 73,
+    WSN             = 74,
+    PVP             = 75,
+    BR_SAT_MON      = 76,
+    SUN_ND          = 77,
+    WB_MON          = 78,
+    WB_EXPAK        = 79,
+    ISO_IP          = 80,
+    VMTP            = 81,
+    SECURE_VMTP     = 82,
+    VINES           = 83,
+    IPTM            = 84,
+    NSFNET_IGP      = 85,
+    DGP             = 86,
+    TCF             = 87,
+    EIGRP           = 88,
+    OSPFIGP         = 89,
+    Sprite_RPC      = 90,
+    LARP            = 91,
+    MTP             = 92,
+    AX_25           = 93,
+    IPIP            = 94,
+    SCC_SP          = 96,
+    ETHERIP         = 97,
+    ENCAP           = 98,
+    GMTP            = 100,
+    IFMP            = 101,
+    PNNI            = 102,
+    PIM             = 103,
+    ARIS            = 104,
+    SCPS            = 105,
+    QNX             = 106,
+    A_N             = 107,
+    IPComp          = 108,
+    SNP             = 109,
+    Compaq_Peer     = 110,
+    IPX_in_IP       = 111,
+    VRRP            = 112,
+    PGM             = 113,
+    L2TP            = 115,
+    DDX             = 116,
+    IATP            = 117,
+    STP             = 118,
+    SRP             = 119,
+    UTI             = 120,
+    SMP             = 121,
+    PTP             = 123,
+    FIRE            = 125,
+    CRTP            = 126,
+    CRUDP           = 127,
+    SSCOPMCE        = 128,
+    IPLT            = 129,
+    SPS             = 130,
+    PIPE            = 131,
+    SCTP            = 132,
+    FC              = 133,
+    RSVP_E2E_IGNORE = 134,
+    UDPLite         = 136,
+    MPLS_in_IP      = 137,
+    manet           = 138,
+    HIP             = 139,
+    Shim6           = 140,
+    WESP            = 141,
+    ROHC            = 142,
+    Ethernet        = 143,
+    AGGFRAG         = 144,
+    NSH             = 145,
+    Reserved        = 255,
+}
+
+/// API Level for get/setsockopt.2
+Socket_API_Level :: enum {
+    // Comes from <bits/socket-constants.h>
+    SOCKET          = 1,
+    // Copy-pasted from protocol numbers
+    TCP             = 6,
+    UDP             = 17,
+    // Comes from <bits/socket.h>
+    RAW             = 255,
+    DECNET          = 261,
+    X25             = 262,
+    PACKET          = 263,
+    ATM             = 264,
+    AAL             = 265,
+    IRDA            = 266,
+    NETBEUI         = 267,
+    LLC             = 268,
+    DCCP            = 269,
+    NETLINK         = 270,
+    TIPC            = 271,
+    RXRPC           = 272,
+    PPPOL2TP        = 273,
+    BLUETOOTH       = 274,
+    PNPIPE          = 275,
+    RDS             = 276,
+    IUCV            = 277,
+    CAIF            = 278,
+    ALG             = 279,
+    NFC             = 280,
+    KCM             = 281,
+    TLS             = 282,
+    XDP             = 283,
+    MPTCP           = 284,
+    MCTP            = 285,
+    SMC             = 286,
+}
+
+/// If Socket_API_Level == .SOCKET, these are the options
+/// you can specify in get/setsockopt.2
+Socket_Option :: enum {
+    DEBUG                         = 1,
+    REUSEADDR                     = 2,
+    TYPE                          = 3,
+    ERROR                         = 4,
+    DONTROUTE                     = 5,
+    BROADCAST                     = 6,
+    SNDBUF                        = 7,
+    RCVBUF                        = 8,
+    SNDBUFFORCE                   = 32,
+    RCVBUFFORCE                   = 33,
+    KEEPALIVE                     = 9,
+    OOBINLINE                     = 10,
+    NO_CHECK                      = 11,
+    PRIORITY                      = 12,
+    LINGER                        = 13,
+    BSDCOMPAT                     = 14,
+    REUSEPORT                     = 15,
+    PASSCRED                      = 16,
+    PEERCRED                      = 17,
+    RCVLOWAT                      = 18,
+    SNDLOWAT                      = 19,
+    RCVTIMEO_OLD                  = 20,
+    SNDTIMEO_OLD                  = 21,
+    SECURITY_AUTHENTICATION       = 22,
+    SECURITY_ENCRYPTION_TRANSPORT = 23,
+    SECURITY_ENCRYPTION_NETWORK   = 24,
+    BINDTODEVICE                  = 25,
+    ATTACH_FILTER                 = 26,
+    DETACH_FILTER                 = 27,
+    GET_FILTER                    = ATTACH_FILTER,
+    PEERNAME                      = 28,
+    ACCEPTCONN                    = 30,
+    PEERSEC                       = 31,
+    PASSSEC                       = 34,
+    MARK                          = 36,
+    PROTOCOL                      = 38,
+    DOMAIN                        = 39,
+    RXQ_OVFL                      = 40,
+    WIFI_STATUS                   = 41,
+    PEEK_OFF                      = 42,
+    NOFCS                         = 43,
+    LOCK_FILTER                   = 44,
+    SELECT_ERR_QUEUE              = 45,
+    BUSY_POLL                     = 46,
+    MAX_PACING_RATE               = 47,
+    BPF_EXTENSIONS                = 48,
+    INCOMING_CPU                  = 49,
+    ATTACH_BPF                    = 50,
+    DETACH_BPF                    = DETACH_FILTER,
+    ATTACH_REUSEPORT_CBPF         = 51,
+    ATTACH_REUSEPORT_EBPF         = 52,
+    CNX_ADVICE                    = 53,
+    TIMESTAMPING_OPT_STATS        = 54,
+    MEMINFO                       = 55,
+    INCOMING_NAPI_ID              = 56,
+    COOKIE                        = 57,
+    TIMESTAMPING_PKTINFO          = 58,
+    PEERGROUPS                    = 59,
+    ZEROCOPY                      = 60,
+    TXTIME                        = 61,
+    BINDTOIFINDEX                 = 62,
+    TIMESTAMP_OLD                 = 29,
+    TIMESTAMPNS_OLD               = 35,
+    TIMESTAMPING_OLD              = 37,
+    TIMESTAMP_NEW                 = 63,
+    TIMESTAMPNS_NEW               = 64,
+    TIMESTAMPING_NEW              = 65,
+    RCVTIMEO_NEW                  = 66,
+    SNDTIMEO_NEW                  = 67,
+    DETACH_REUSEPORT_BPF          = 68,
+    PREFER_BUSY_POLL              = 69,
+    BUSY_POLL_BUDGET              = 70,
+    NETNS_COOKIE                  = 71,
+    BUF_LOCK                      = 72,
+    RESERVE_MEM                   = 73,
+    TXREHASH                      = 74,
+    RCVMARK                       = 75,
+    // Hardcoded 64-bit Time. It's time to move on.
+    TIMESTAMP                     = TIMESTAMP_NEW,
+    TIMESTAMPNS                   = TIMESTAMPNS_NEW,
+    TIMESTAMPING                  = TIMESTAMPING_NEW,
+    RCVTIMEO                      = RCVTIMEO_NEW,
+    SNDTIMEO                      = SNDTIMEO_NEW,
+}
+
+Socket_UDP_Option :: enum {
+    CORK                   = 1,
+    ENCAP                  = 100,
+    NO_CHECK6_TX           = 101,
+    NO_CHECK6_RX           = 102,
+    SEGMENT                = 103,
+    GRO                    = 104,
+}
+
+UPD_Encapsulation :: enum {
+    ENCAP_ESPINUDP_NON_IKE = 1,
+    ENCAP_ESPINUDP         = 2,
+    ENCAP_L2TPINUDP        = 3,
+    ENCAP_GTP0             = 4,
+    ENCAP_GTP1U            = 5,
+}
+
+Socket_TCP_Option :: enum {
+    NODELAY              = 1,
+    MAXSEG               = 2,
+    CORK                 = 3,
+    KEEPIDLE             = 4,
+    KEEPINTVL            = 5,
+    KEEPCNT              = 6,
+    SYNCNT               = 7,
+    LINGER2              = 8,
+    DEFER_ACCEPT         = 9,
+    WINDOW_CLAMP         = 10,
+    INFO                 = 11,
+    QUICKACK             = 12,
+    CONGESTION           = 13,
+    MD5SIG               = 14,
+    COOKIE_TRANSACTIONS  = 15,
+    THIN_LINEAR_TIMEOUTS = 16,
+    THIN_DUPACK          = 17,
+    USER_TIMEOUT         = 18,
+    REPAIR               = 19,
+    REPAIR_QUEUE         = 20,
+    QUEUE_SEQ            = 21,
+    REPAIR_OPTIONS       = 22,
+    FASTOPEN             = 23,
+    TIMESTAMP            = 24,
+    NOTSENT_LOWAT        = 25,
+    CC_INFO              = 26,
+    SAVE_SYN             = 27,
+    SAVED_SYN            = 28,
+    REPAIR_WINDOW        = 29,
+    FASTOPEN_CONNECT     = 30,
+    ULP                  = 31,
+    MD5SIG_EXT           = 32,
+    FASTOPEN_KEY         = 33,
+    FASTOPEN_NO_COOKIE   = 34,
+    ZEROCOPY_RECEIVE     = 35,
+    INQ                  = 36,
+    CM_INQ               = INQ,
+    TX_DELAY             = 37,
+}
+
+/// Bits for Socket_Msg
+Socket_Msg_Bits :: enum {
+    OOB             = 0,
+    PEEK            = 1,
+    DONTROUTE       = 2,
+    TRYHARD         = DONTROUTE,
+    CTRUNC          = 3,
+    PROXY           = 4,
+    TRUNC           = 5,
+    DONTWAIT        = 6,
+    EOR             = 7,
+    WAITALL         = 8,
+    FIN             = 9,
+    SYN             = 10,
+    CONFIRM         = 11,
+    RST             = 12,
+    ERRQUEUE        = 13,
+    NOSIGNAL        = 14,
+    MORE            = 15,
+    WAITFORONE      = 16,
+    BATCH           = 18,
+    ZEROCOPY        = 22,
+    FASTOPEN        = 29,
+    CMSG_CLOEXEC    = 30,
+}
+
+/// Argument to shutdown.2
+Shutdown_How :: enum i32 {
+    RD   = 0,
+    WR   = 1,
+    RDWR = 2,
+}
+
+/// Second argument to futex.2 syscall
+Futex_Op :: enum u32 {
+    WAIT              = 0,
+    WAKE              = 1,
+    FD                = 2,
+    REQUEUE           = 3,
+    CMP_REQUEUE       = 4,
+    WAKE_OP           = 5,
+    LOCK_PI           = 6,
+    UNLOCK_PI         = 7,
+    TRYLOCK_PI        = 8,
+    WAIT_BITSET       = 9,
+    WAKE_BITSET       = 10,
+    WAIT_REQUEUE_PI   = 11,
+    CMP_REQUEUE_PI    = 12,
+    LOCK_PI2          = 13,
+}
+
+/// Bits for Futex_Flags
+Futex_Flags_Bits :: enum {
+    PRIVATE    = 7,
+    REALTIME   = 8,
+}
+
+/// Kind of operation on futex, see FUTEX_WAKE_OP
+Futex_Arg_Op :: enum {
+    SET      = 0,  /* uaddr2 =       oparg; */
+    ADD      = 1,  /* uaddr2 +=      oparg; */
+    OR       = 2,  /* uaddr2 |=      oparg; */
+    ANDN     = 3,  /* uaddr2 &=     ~oparg; */
+    XOR      = 4,  /* uaddr2 ^=      oparg; */
+    PO2_SET  = 0,  /* uaddr2 =    1<<oparg; */
+    PO2_ADD  = 1,  /* uaddr2 +=   1<<oparg; */
+    PO2_OR   = 2,  /* uaddr2 |=   1<<oparg; */
+    PO2_ANDN = 3,  /* uaddr2 &= ~(1<<oparg); */
+    PO2_XOR  = 4,  /* uaddr2 ^=   1<<oparg; */
+}
+
+/// Kind of comparison operation on futex, see FUTEX_WAKE_OP
+Futex_Cmp_Op :: enum {
+    EQ = 0,  /* if (oldval == cmparg) wake */
+    NE = 1,  /* if (oldval != cmparg) wake */
+    LT = 2,  /* if (oldval < cmparg) wake */
+    LE = 3,  /* if (oldval <= cmparg) wake */
+    GT = 4,  /* if (oldval > cmparg) wake */
+    GE = 5,  /* if (oldval >= cmparg) wake */
+}
+
+/// The kind of resource limits
+RLimit_Kind :: enum i32 {
+    CPU        = 0,
+    FSIZE      = 1,
+    DATA       = 2,
+    STACK      = 3,
+    CORE       = 4,
+    RSS        = 5,
+    NOFILE     = 7,
+    AS         = 9,
+    NPROC      = 6,
+    MEMLOCK    = 8,
+    LOCKS      = 10,
+    SIGPENDING = 11,
+    MSGQUEUE   = 12,
+    NICE       = 13,
+    RTPRIO     = 14,
+    RTTIME     = 15,
+    NLIMITS    = 16,
+}
+
+/// Represents the user of resources
+RUsage_Who :: enum i32 {
+    CHILDREN = -1,
+    SELF     =  0,
+    THREAD   =  1,
+    LWP      =  THREAD,
+}
+
+/// Bits for Personality_Flags
+UNAME26            :: 17
+ADDR_NO_RANDOMIZE  :: 18
+FDPIC_FUNCPTRS     :: 19
+MMAP_PAGE_ZERO     :: 20
+ADDR_COMPAT_LAYOUT :: 21
+READ_IMPLIES_EXEC  :: 22
+ADDR_LIMIT_32BIT   :: 23
+SHORT_INODE        :: 24
+WHOLE_SECONDS      :: 25
+STICKY_TIMEOUTS    :: 26
+ADDR_LIMIT_3GB     :: 27
+
+/// Personality type
+/// These go into the bottom 8 bits of the personality value
+PER_LINUX       :: 0x0000
+PER_LINUX_32BIT :: 0x0000 | ADDR_LIMIT_32BIT
+PER_LINUX_FDPIC :: 0x0000 | FDPIC_FUNCPTRS
+PER_SVR4        :: 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO
+PER_SVR3        :: 0x0002 | STICKY_TIMEOUTS | SHORT_INODE
+PER_SCOSVR3     :: 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE
+PER_OSR5        :: 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS
+PER_WYSEV386    :: 0x0004 | STICKY_TIMEOUTS | SHORT_INODE
+PER_ISCR4       :: 0x0005 | STICKY_TIMEOUTS
+PER_BSD         :: 0x0006
+PER_SUNOS       :: 0x0006 | STICKY_TIMEOUTS
+PER_XENIX       :: 0x0007 | STICKY_TIMEOUTS | SHORT_INODE
+PER_LINUX32     :: 0x0008
+PER_LINUX32_3GB :: 0x0008 | ADDR_LIMIT_3GB
+PER_IRIX32      :: 0x0009 | STICKY_TIMEOUTS
+PER_IRIXN32     :: 0x000a | STICKY_TIMEOUTS
+PER_IRIX64      :: 0x000b | STICKY_TIMEOUTS
+PER_RISCOS      :: 0x000c
+PER_SOLARIS     :: 0x000d | STICKY_TIMEOUTS
+PER_UW7         :: 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO
+PER_OSF4        :: 0x000f
+PER_HPUX        :: 0x0010
+PER_MASK        :: 0x00ff
+

+ 199 - 0
core/sys/linux/constants.odin

@@ -0,0 +1,199 @@
+
+package linux
+
+/// Special file descriptor to pass to `*at` functions to specify
+/// that relative paths are relative to current directory
+AT_FDCWD :: Fd(-100)
+
+/// Special value to put into timespec for utimensat() to set timestamp to the current time
+UTIME_NOW  :: uint((1 << 30) - 1)
+
+/// Special value to put into the timespec for utimensat() to leave the corresponding field of the timestamp unchanged
+UTIME_OMIT :: uint((1 << 30) - 2)
+
+/// For wait4: Pass this pid to wait for any process
+WAIT_ANY    :: Pid(-1)
+
+/// For wait4: Pass this pid to wait for any process in current process group
+WAIT_MYPGRP :: Pid(0)
+
+/// Maximum priority (aka nice value) for the process
+PRIO_MAX :: 20
+
+/// Minimum priority (aka nice value) for the process
+PRIO_MIN :: -20
+
+SIGRTMIN :: Signal(32)
+SIGRTMAX :: Signal(64)
+
+S_IFMT   :: Mode{.IFREG, .IFDIR, .IFCHR, .IFFIFO}
+S_IFSOCK :: Mode{.IFREG, .IFDIR}
+S_IFLNK  :: Mode{.IFREG, .IFCHR}
+S_IFBLK  :: Mode{.IFDIR, .IFCHR}
+S_IFFIFO :: Mode{.IFFIFO}
+S_IFCHR  :: Mode{.IFCHR}
+S_IFDIR  :: Mode{.IFDIR}
+S_IFREG  :: Mode{.IFREG}
+
+/// Checks the Mode bits to see if the file is a named pipe (FIFO)
+S_ISFIFO :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFFIFO  == (m & S_IFMT))}
+
+/// Check the Mode bits to see if the file is a character device
+S_ISCHR  :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFCHR  == (m & S_IFMT))}
+    
+/// Check the Mode bits to see if the file is a directory
+S_ISDIR  :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFDIR  == (m & S_IFMT))}
+
+/// Check the Mode bits to see if the file is a register
+S_ISREG  :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFREG  == (m & S_IFMT))}
+
+/// Check the Mode bits to see if the file is a socket
+S_ISSOCK :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFSOCK == (m & S_IFMT))}
+
+/// Check the Mode bits to see if the file is a symlink
+S_ISLNK  :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFLNK  == (m & S_IFMT))}
+
+/// Check the Mode bits to see if the file is a block device
+S_ISBLK  :: #force_inline proc "contextless" (m: Mode) -> bool {return (S_IFBLK  == (m & S_IFMT))}
+
+/// For access.2 syscall family: instruct to check if the file exists
+F_OK :: Mode{}
+
+/// For access.2 syscall family: instruct to check if the file is executable
+X_OK :: Mode{.IXOTH}
+
+/// For access.2 syscall family: instruct to check if the file is writeable
+W_OK :: Mode{.IWOTH}
+
+/// For access.2 syscall family: instruct to check if the file is readable
+R_OK :: Mode{.IROTH}
+
+/// The stats you get by calling `stat`
+STATX_BASIC_STATS :: Statx_Mask {
+    .TYPE,
+    .MODE,
+    .NLINK,
+    .UID,
+    .GID,
+    .ATIME,
+    .MTIME,
+    .CTIME,
+    .INO,
+    .SIZE,
+    .BLOCKS,
+}
+
+
+FCntl_Command_DUPFD            :: distinct FCntl_Command
+FCntl_Command_GETFD            :: distinct FCntl_Command
+FCntl_Command_SETFD            :: distinct FCntl_Command
+FCntl_Command_GETFL            :: distinct FCntl_Command
+FCntl_Command_SETFL            :: distinct FCntl_Command
+FCntl_Command_GETLK            :: distinct FCntl_Command
+FCntl_Command_SETLK            :: distinct FCntl_Command
+FCntl_Command_SETLKW           :: distinct FCntl_Command
+FCntl_Command_DUPFD_CLOEXEC    :: distinct FCntl_Command
+FCntl_Command_SETOWN           :: distinct FCntl_Command
+FCntl_Command_GETOWN           :: distinct FCntl_Command
+FCntl_Command_SETSIG           :: distinct FCntl_Command
+FCntl_Command_GETSIG           :: distinct FCntl_Command
+FCntl_Command_SETOWN_EX        :: distinct FCntl_Command
+FCntl_Command_GETOWN_EX        :: distinct FCntl_Command
+FCntl_Command_SETLEASE         :: distinct FCntl_Command
+FCntl_Command_GETLEASE         :: distinct FCntl_Command
+FCntl_Command_NOTIFY           :: distinct FCntl_Command
+FCntl_Command_SETPIPE_SZ       :: distinct FCntl_Command
+FCntl_Command_GETPIPE_SZ       :: distinct FCntl_Command
+FCntl_Command_ADD_SEALS        :: distinct FCntl_Command
+FCntl_Command_GET_SEALS        :: distinct FCntl_Command
+FCntl_Command_GET_RW_HINT      :: distinct FCntl_Command
+FCntl_Command_SET_RW_HINT      :: distinct FCntl_Command
+FCntl_Command_GET_FILE_RW_HINT :: distinct FCntl_Command
+FCntl_Command_SET_FILE_RW_HINT :: distinct FCntl_Command
+F_DUPFD            :: FCntl_Command_DUPFD(.DUPFD)
+F_GETFD            :: FCntl_Command_GETFD(.GETFD)
+F_SETFD            :: FCntl_Command_SETFD(.SETFD)
+F_GETFL            :: FCntl_Command_GETFL(.GETFL)
+F_SETFL            :: FCntl_Command_SETFL(.SETFL)
+// F_GETLK64          :: FCntl_Command_GETLK64(.GETLK64)
+// F_SETLK64          :: FCntl_Command_SETLK64(.SETLK64)
+// F_SETLKW64         :: FCntl_Command_SETLKW64(.SETLKW64)
+F_GETLK            :: FCntl_Command_GETLK(.GETLK)
+F_SETLK            :: FCntl_Command_SETLK(.SETLK)
+F_SETLKW           :: FCntl_Command_SETLKW(.SETLKW)
+F_DUPFD_CLOEXEC    :: FCntl_Command_DUPFD_CLOEXEC(.DUPFD_CLOEXEC)
+F_SETOWN           :: FCntl_Command_SETOWN(.SETOWN)
+F_GETOWN           :: FCntl_Command_GETOWN(.GETOWN)
+F_SETSIG           :: FCntl_Command_SETSIG(.SETSIG)
+F_GETSIG           :: FCntl_Command_GETSIG(.GETSIG)
+F_SETOWN_EX        :: FCntl_Command_SETOWN_EX(.SETOWN_EX)
+F_GETOWN_EX        :: FCntl_Command_GETOWN_EX(.GETOWN_EX)
+F_SETLEASE         :: FCntl_Command_SETLEASE(.SETLEASE)
+F_GETLEASE         :: FCntl_Command_GETLEASE(.GETLEASE)
+F_NOTIFY           :: FCntl_Command_NOTIFY(.NOTIFY)
+F_SETPIPE_SZ       :: FCntl_Command_SETPIPE_SZ(.SETPIPE_SZ)
+F_GETPIPE_SZ       :: FCntl_Command_GETPIPE_SZ(.GETPIPE_SZ)
+F_ADD_SEALS        :: FCntl_Command_ADD_SEALS(.ADD_SEALS)
+F_GET_SEALS        :: FCntl_Command_GET_SEALS(.GET_SEALS)
+F_GET_RW_HINT      :: FCntl_Command_GET_RW_HINT(.GET_RW_HINT)
+F_SET_RW_HINT      :: FCntl_Command_SET_RW_HINT(.SET_RW_HINT)
+F_GET_FILE_RW_HINT :: FCntl_Command_GET_FILE_RW_HINT(.GET_FILE_RW_HINT)
+F_SET_FILE_RW_HINT :: FCntl_Command_SET_FILE_RW_HINT(.SET_FILE_RW_HINT)
+
+Socket_API_Level_Sock :: distinct Socket_API_Level
+Socket_API_Level_TCP  :: distinct Socket_API_Level
+Socket_API_Level_UDP  :: distinct Socket_API_Level
+Socket_API_Level_Raw  :: distinct Socket_API_Level
+
+SOL_SOCKET :: Socket_API_Level_Sock(.SOCKET)
+SOL_TCP    :: Socket_API_Level_TCP(.TCP)
+SOL_UDP    :: Socket_API_Level_UDP(.UDP)
+SOL_RAW    :: Socket_API_Level_Raw(.RAW)
+
+Futex_Wait_Type            :: distinct Futex_Op
+Futex_Wake_Type            :: distinct Futex_Op
+Futex_Fd_Type              :: distinct Futex_Op
+Futex_Requeue_Type         :: distinct Futex_Op
+Futex_Cmp_Requeue_Type     :: distinct Futex_Op
+Futex_Wake_Op_Type         :: distinct Futex_Op
+Futex_Lock_Pi_Type         :: distinct Futex_Op
+Futex_Unlock_Pi_Type       :: distinct Futex_Op
+Futex_Trylock_Pi_Type      :: distinct Futex_Op
+Futex_Wait_Bitset_Type     :: distinct Futex_Op
+Futex_Wake_Bitset_Type     :: distinct Futex_Op
+Futex_Wait_requeue_Pi_Type :: distinct Futex_Op
+Futex_Cmp_requeue_Pi_Type  :: distinct Futex_Op
+Futex_Lock_Pi2_Type        :: distinct Futex_Op
+
+/// Wait on futex wakeup signal
+FUTEX_WAIT            :: Futex_Wait_Type(.WAIT)
+
+/// Wake up other processes waiting on the futex
+FUTEX_WAKE            :: Futex_Wake_Type(.WAKE)
+
+/// Not implemented. Basically, since
+FUTEX_FD              :: Futex_Fd_Type(.FD)
+
+/// Requeue waiters from one futex to another
+FUTEX_REQUEUE         :: Futex_Requeue_Type(.REQUEUE)
+
+/// Requeue waiters from one futex to another if the value at mutex matches
+FUTEX_CMP_REQUEUE     :: Futex_Cmp_Requeue_Type(.CMP_REQUEUE)
+
+/// See man pages, I'm not describing it here
+FUTEX_WAKE_OP         :: Futex_Wake_Op_Type(.WAKE_OP)
+
+/// Wait on a futex, but the value is a bitset
+FUTEX_WAIT_BITSET     :: Futex_Wait_Bitset_Type(.WAIT_BITSET)
+
+/// Wait on a futex, but the value is a bitset
+FUTEX_WAKE_BITSET     :: Futex_Wake_Bitset_Type(.WAKE_BITSET)
+
+// TODO(flysand): Priority inversion futexes
+FUTEX_LOCK_PI         :: Futex_Lock_Pi_Type(.LOCK_PI)
+FUTEX_UNLOCK_PI       :: Futex_Unlock_Pi_Type(.UNLOCK_PI)
+FUTEX_TRYLOCK_PI      :: Futex_Trylock_Pi_Type(.TRYLOCK_PI)
+FUTEX_WAIT_REQUEUE_PI :: Futex_Wait_requeue_Pi_Type(.WAIT_REQUEUE_PI)
+FUTEX_CMP_REQUEUE_PI  :: Futex_Cmp_requeue_Pi_Type(.CMP_REQUEUE_PI)
+FUTEX_LOCK_PI2        :: Futex_Lock_Pi2_Type(.LOCK_PI2)
+

+ 150 - 0
core/sys/linux/helpers.odin

@@ -0,0 +1,150 @@
+//+build linux
+package linux
+
+import "core:intrinsics"
+
+// Note(flysand): In the case of syscall let's get rid of extra
+// casting. First of all, let these syscalls return int, because
+// we'll need to check for Errno anyway. Second of all
+// most parameters are going to be trivially-castable to
+// uintptr, so we'll have that.
+
+@(private)
+syscall0 :: #force_inline proc "contextless" (nr: uintptr) -> int {
+	return cast(int) intrinsics.syscall(nr)
+}
+
+@(private)
+syscall1 :: #force_inline proc "contextless" (nr: uintptr, p1: $T) -> int
+where
+	size_of(p1) <= size_of(uintptr)
+{
+	return cast(int) intrinsics.syscall(nr, cast(uintptr) p1)
+}
+
+@(private)
+syscall2 :: #force_inline proc "contextless" (nr: uintptr,p1: $T1, p2: $T2) -> int
+where
+	size_of(p1) <= size_of(uintptr) &&
+	size_of(p2) <= size_of(uintptr) 
+{
+	return cast(int) intrinsics.syscall(nr,
+        cast(uintptr) p1, cast(uintptr) p2)
+}
+
+@(private)
+syscall3 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3) -> int
+where
+	size_of(p1) <= size_of(uintptr) &&
+	size_of(p2) <= size_of(uintptr) &&
+	size_of(p3) <= size_of(uintptr)
+{
+	return cast(int) intrinsics.syscall(nr,
+        cast(uintptr) p1,
+        cast(uintptr) p2,
+        cast(uintptr) p3)
+}
+
+@(private)
+syscall4 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4) -> int
+where
+	size_of(p1) <= size_of(uintptr) &&
+	size_of(p2) <= size_of(uintptr) &&
+	size_of(p3) <= size_of(uintptr) &&
+	size_of(p4) <= size_of(uintptr)
+{
+	return cast(int) intrinsics.syscall(nr,
+        cast(uintptr) p1,
+        cast(uintptr) p2,
+        cast(uintptr) p3,
+        cast(uintptr) p4)
+}
+
+@(private)
+syscall5 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5) -> int
+where
+	size_of(p1) <= size_of(uintptr) &&
+	size_of(p2) <= size_of(uintptr) &&
+	size_of(p3) <= size_of(uintptr) &&
+	size_of(p4) <= size_of(uintptr) &&
+	size_of(p5) <= size_of(uintptr)
+{
+	return cast(int) intrinsics.syscall(nr,
+        cast(uintptr) p1,
+        cast(uintptr) p2,
+        cast(uintptr) p3,
+        cast(uintptr) p4,
+        cast(uintptr) p5)
+}
+
+@(private)
+syscall6 :: #force_inline proc "contextless" (nr: uintptr, p1: $T1, p2: $T2, p3: $T3, p4: $T4, p5: $T5, p6: $T6) -> int
+where
+	size_of(p1) <= size_of(uintptr) &&
+	size_of(p2) <= size_of(uintptr) &&
+	size_of(p3) <= size_of(uintptr) &&
+	size_of(p4) <= size_of(uintptr) &&
+	size_of(p5) <= size_of(uintptr) &&
+	size_of(p6) <= size_of(uintptr)
+{
+	return cast(int) intrinsics.syscall(nr,
+        cast(uintptr) p1,
+        cast(uintptr) p2,
+        cast(uintptr) p3,
+        cast(uintptr) p4,
+        cast(uintptr) p5,
+        cast(uintptr) p6)
+}
+
+syscall :: proc {syscall0, syscall1, syscall2, syscall3, syscall4, syscall5, syscall6}
+
+// Note(bumbread): This should shrug off a few lines from every syscall.
+// Since not any type can be trivially casted to another type, we take two arguments:
+// the final type to cast to, and the type to transmute to before casting.
+// One transmute + one cast should allow us to get to any type we might want
+// to return from a syscall wrapper.
+@(private)
+errno_unwrap3 :: #force_inline proc "contextless" (ret: $P, $T: typeid, $U: typeid) -> (T, Errno)
+where
+    intrinsics.type_is_ordered_numeric(P)
+{
+    if ret < 0 {
+        default_value: T
+        return default_value, Errno(-ret)
+    } else {
+        return cast(T) transmute(U) ret, Errno(.NONE)
+    }
+}
+
+@(private)
+errno_unwrap2 :: #force_inline proc "contextless" (ret: $P, $T: typeid) -> (T, Errno) {
+    if ret < 0 {
+        default_value: T
+        return default_value, Errno(-ret)
+    } else {
+        return cast(T) ret, Errno(.NONE)
+    }
+}
+
+@(private)
+errno_unwrap :: proc {errno_unwrap2, errno_unwrap3}
+
+// Note(flysand): 32-bit architectures sometimes take in a 64-bit argument in a
+// register pair. This function should help me avoid typing the same code a few times..
+when size_of(int) == 4 {
+    // xxx64 system calls take some parameters as pairs of ulongs rather than a single pointer
+    @(private)
+    compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (hi: uint, lo: uint) {
+        no_sign := uint(a)
+        hi = uint(no_sign >> 32)
+        lo = uint(no_sign & 0xffff_ffff)
+        return
+    }
+} else {
+    // ... and on 64-bit architectures it's just a long
+    @(private)
+    compat64_arg_pair :: #force_inline proc "contextless" (a: i64) -> (uint) {
+        return uint(a)
+    }
+}
+

+ 2038 - 0
core/sys/linux/sys.odin

@@ -0,0 +1,2038 @@
+//+build linux
+package linux
+
+import "core:intrinsics"
+
+
+/// Read data from file into the buffer
+/// Returns the number of bytes successfully read, which may be less than the size
+/// of the buffer even if the termination is successfull
+///
+/// Available since Linux 1.0
+/// Before Linux 3.14, this operation is not atomic (i.e. not thread safe).
+read :: proc "contextless" (fd: Fd, buf: []$T) -> (int, Errno) {
+    ret := syscall(SYS_read, fd, raw_data(buf), len(buf) * size_of(T))
+    return errno_unwrap(ret, int)
+}
+
+/// Write the data from a buffer into the file
+/// Returns the number of bytes successfully written, which may be less than the size
+/// of the buffer, even if the termination is successfull
+/// When using direct I/O, error doesn't mean the write has failed. Partial data may
+/// have been written.
+/// If .Eintr is returned, the write operation has failed due to interrupt. You'll probably
+/// need to restart this syscall
+///
+/// Available since Linux 1.0
+/// Before Linux 3.14 this operation is not atomic (i.e. not thread safe)
+write :: proc "contextless" (fd: Fd, buf: []$T) -> (int, Errno) {
+    ret := syscall(SYS_write, fd, raw_data(buf), len(buf)*size_of(T))
+    return errno_unwrap(ret, int)
+}
+
+/// Open file, get the file descriptor
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+open :: proc "contextless" (name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_openat, AT_FDCWD, transmute(uintptr) name, transmute(u32) mode)
+        return errno_unwrap(ret, Fd)
+    } else {
+        ret := syscall(SYS_open, transmute(uintptr) name, transmute(u32) mode)
+        return errno_unwrap(ret, Fd)
+    }
+}
+
+/// Close the file
+/// Available since Linux 1.0
+close :: proc "contextless" (fd: Fd) -> (Errno) {
+    ret := syscall(SYS_close, fd)
+    return Errno(-ret)
+}
+
+/// Get file status
+///
+/// Returns information about the file in struct pointed to by `stat` parameter.
+///
+/// Available since Linux 1.0
+/// For 32-bit systems a different syscall is used that became available since 2.4
+/// Not available on arm64
+stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) {
+    when size_of(int) == 8 {
+        when ODIN_ARCH == .arm64 {
+            ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat)
+            return Errno(-ret)
+        } else {
+            ret := syscall(SYS_stat, cast(rawptr) filename, stat)
+            return Errno(-ret)
+        }
+    } else {
+        ret := syscall(SYS_stat64, cast(rawptr) filename, stat)
+        return Errno(-ret)
+    }
+}
+
+/// Get file status from file descriptor
+///
+/// Returns information about the file in struct pointed to by `stat` parameter.
+///
+/// Available since Linux 1.0
+/// For 32-bit systems a different syscall is used that became available since 2.4
+fstat :: proc "contextless" (fd: Fd, stat: ^Stat) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_fstat, stat)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fstat64, stat)
+        return Errno(-ret)
+    }
+}
+
+/// Get information about the file that's potentially a symbolic link
+/// The information is returned in a struct pointed to by `stat` parameter.
+/// The difference with stat, fstat is that if the file is a symbolic link,
+/// stat and fstat will dereference the link. lstat doesn't dereference symlinks
+///
+/// Available since Linux 1.0
+/// For 32-bit systems a different syscall is used that became available since 2.4
+/// Not available on arm64
+lstat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) {
+    when size_of(int) == 8 {
+        when ODIN_ARCH == .arm64 {
+            return fstatat(AT_FDCWD, filename, stat, {.SYMLINK_NOFOLLOW})
+        } else {
+            ret := syscall(SYS_lstat, cast(rawptr) filename, stat)
+            return Errno(-ret)
+        }
+    } else {
+        ret := syscall(SYS_lstat64, cast(rawptr) filename, stat)
+        return Errno(-ret)
+    }
+}
+
+/// Wait on event on a file descriptor
+/// Available since Linux 2.2
+poll :: proc "contextless" (fds: []Poll_Fd, timeout: i32) -> (i32, Errno) {
+    when ODIN_ARCH == .arm64 {
+        seconds := cast(uint) timeout / 1000
+        nanoseconds := cast(uint) (timeout % 1000) * 1_000_000
+        timeout_spec := Time_Spec{seconds, nanoseconds}
+        ret := syscall(SYS_ppoll, raw_data(fds), len(fds), &timeout_spec, 0, 0)
+        return errno_unwrap(ret, i32)
+    } else {
+        ret := syscall(SYS_poll, raw_data(fds), len(fds), timeout)
+        return errno_unwrap(ret, i32)
+    }
+}
+
+
+/// Seek the file stream to specified offset
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 1.2
+lseek :: proc "contextless" (fd: Fd, off: i64, whence: Seek_Whence) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_lseek, fd, off, whence)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS__llseek, fd, compat64_arg_pair(off), whence)
+        return Errno(-ret)
+    }
+}
+
+/// Map files into memory
+/// Available since Linux 1.0
+/// On 32-bit platforms since Linux 1.0
+mmap :: proc "contextless" (addr: uintptr, size: uint, prot: Mem_Protection, flags: Map_Flags, fd: Fd = Fd(-1), offset: i64 = 0) -> (rawptr, Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_mmap, addr, size, transmute(i32) prot, transmute(i32) flags, fd, offset)
+        return errno_unwrap(ret, rawptr, uintptr)
+    } else {
+        ret := syscall(SYS_mmap2, addr, size, transmute(i32) prot, transmute(i32) flags, fd, cast(uintptr)(offset/4096))
+        return errno_unwrap(ret, rawptr, uintptr)
+    }
+}
+
+/// Protect memory region
+mprotect :: proc "contextless" (addr: rawptr, size: uint, prot: Mem_Protection) -> (Errno) {
+    ret := syscall(SYS_mprotect, addr, size, transmute(i32) prot)
+    return Errno(-ret)
+}
+
+/// Unmap memory
+/// Available since Linux 1.0
+munmap :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) {
+    ret := syscall(SYS_mmap, addr, size)
+    return Errno(-ret)
+}
+
+// TODO(flysand): brk
+
+/// Alter an action taken by a process
+rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action, old_sigaction: ^Sig_Action) -> Errno {
+    ret := syscall(SYS_rt_sigaction, sig, sigaction, old_sigaction, size_of(Sig_Set))
+    return Errno(-ret)
+}
+
+/// Examime and alter blocked signals
+/// Available since Linux 2.2
+rt_sigprocmask :: proc "contextless" (mask_kind: Sig_Mask_Kind, new_set: ^Sig_Set, old_set: ^Sig_Set) -> Errno {
+    ret := syscall(SYS_rt_sigprocmask, mask_kind, new_set, old_set, size_of(Sig_Set))
+    return Errno(-ret)
+}
+
+// TODO(flysand): rt_sigreturn
+
+// TODO(flysand): ioctl
+
+/// Read the file at a specified offset
+/// Note, it is not an error to return less bytes than requested
+/// Available since Linux 2.2
+pread :: proc "contextless" (fd: Fd, buf: []$T, offset: i64) -> (int, Errno) {
+    ret := syscall(SYS_pread64, fd, raw_data(buf), compat64_arg_pair(len(buf)*size_of(T)))
+    return errno_unwrap(ret, int)
+}
+
+/// Read the file at a specified offset
+/// Note, it is not an error to return less bytes than requested
+/// Available since Linux 2.2
+pwrite :: proc "contextless" (fd: Fd, buf: []$T, offset: i64) -> (int, Errno) {
+    ret := syscall(SYS_pwrite64, fd, raw_data(buf), compat64_arg_pair(len(buf)*size_of(T)))
+    return errno_unwrap(ret, int)
+}
+
+// TODO(flysand): readv
+
+// TODO(flysand): writev
+
+/// Check user permissions for a file
+/// If Mode is F_OK, checks whether the file exists
+/// Similarly, X_OK, W_OK, R_OK check if the file is executable, writeable, readable respectively
+/// Available since Linux 1.0
+/// For ARM64 available since Linux 2.6.16
+access :: proc "contextless" (name: cstring, mode: Mode = F_OK) -> (bool, Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_faccessat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode)
+        return errno_unwrap(ret, bool)
+    } else {
+        ret := syscall(SYS_access, cast(rawptr) name, transmute(u32) mode)
+        return errno_unwrap(ret, bool)
+    }
+}
+
+/// Create a pipe
+/// Available since Linux 2.6.27
+pipe2 :: proc "contextless" (pipes: ^[2]Fd, flags: Open_Flags) -> (Errno) {
+    ret := syscall(SYS_pipe2, pipes, transmute(u32) flags)
+    return Errno(-ret)
+}
+
+// TODO(flysand): select
+
+// TODO(flysand): sched_yield
+
+// TODO(flysand): add docs here
+mremap :: proc "contextless" (old_addr: rawptr, old_size: uint, new_size: uint, flags: MRemap_Flags, new_addr: uintptr = 0) -> (rawptr, Errno) {
+    if .FIXED in flags {
+        ret := syscall(SYS_mremap, old_addr, old_size, new_size, transmute(i32) flags, new_addr)
+        return errno_unwrap(ret, rawptr, rawptr)
+    } else {
+        ret := syscall(SYS_mremap, old_addr, old_size, new_size, transmute(i32) flags)
+        return errno_unwrap(ret, rawptr, rawptr)
+    }
+}
+
+/// Sync file with memory map
+/// Available since Linux 2.0
+msync :: proc "contextless" (addr: rawptr, size: uint, flags: MSync_Flags) -> (Errno) {
+    ret := syscall(SYS_msync, addr, size, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+// TODO(flysand): mincore
+
+/// Give advice about use of memory
+/// Available since Linux 2.4
+madvise :: proc "contextless" (addr: rawptr, size: uint, advice: MAdvice) -> (Errno) {
+    ret := syscall(SYS_madvise, addr, size, advice)
+    return Errno(-ret)
+}
+
+// TODO(flysand): shmget
+
+// TODO(flysand): shmat
+
+// TODO(flysand): shmctl
+
+/// Allocate a new file descriptor that refers to the same file as the one provided
+/// Available since Linux 1.0
+dup :: proc "contextless" (fd: Fd) -> (Fd, Errno) {
+    ret := syscall(SYS_dup, fd)
+    return errno_unwrap(ret, Fd)
+}
+
+/// Adjust an existing file descriptor to point to the same file as `old`
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.27
+dup2 :: proc "contextless" (old: Fd, new: Fd) -> (Fd, Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_dup3, old, new, 0)
+        return errno_unwrap(ret, Fd)
+    } else {
+        ret := syscall(SYS_dup2, old, new)
+        return errno_unwrap(ret, Fd)
+    }
+}
+
+// TODO(flysand): pause
+
+// TODO(flysand): nanosleep
+
+// TODO(flysand): getitimer
+
+// TODO(flysand): alarm
+
+// TODO(flysand): setitimer
+
+/// Returns the thread group ID of the current process
+/// Note that it doesn't return the pid, despite it's name.
+/// Available since Linux 1.0
+getpid :: proc "contextless" () -> Pid {
+    return cast(Pid) syscall(SYS_getpid)
+}
+
+// TODO(flysand): sendfile
+
+/// Create a socket file descriptor
+/// Available since Linux 2.0
+socket :: proc "contextless" (domain: Address_Family, socktype: Socket_Type, sockflags: Socket_FD_Flags, protocol: Protocol) -> (Fd, Errno) {
+    sock_type_flags: int = cast(int) socktype | transmute(int) sockflags
+    ret := syscall(SYS_socket, domain, sock_type_flags, protocol)
+    return errno_unwrap(ret, Fd)
+}
+
+/// Connect the socket to the address
+/// Available since Linux 2.0
+connect :: proc "contextless" (sock: Fd, addr: ^$T) -> (Errno)
+where
+    T == Sock_Addr_In ||
+    T == Sock_Addr_In6 ||
+    T == Sock_Addr_Any
+{
+    ret := syscall(SYS_connect, sock, addr, size_of(T))
+    return Errno(-ret)
+}
+
+/// Accept a pending connection or block until new connection appears
+/// Depends on Sock_FD_Flags of the `sock` parameter.
+/// Available since Linux 2.0
+accept :: proc "contextless" (sock: Fd, addr: ^$T, sockflags: Socket_FD_Flags = {}) -> (Fd, Errno)
+where
+    T == Sock_Addr_In ||
+    T == Sock_Addr_In6 ||
+    T == Sock_Addr_Any
+{
+    ret := syscall(SYS_accept4, sock, addr, size_of(T), transmute(int) sockflags)
+    return errno_unwrap(ret, Fd)
+}
+
+// TODO(flysand): Rewrite recvfrom and sendto to use default parameters
+recvfrom :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg, addr: ^$T) -> (int, Errno)
+where
+    T == Sock_Addr_In ||
+    T == Sock_Addr_In6 ||
+    T == Sock_Addr_Any
+{
+    ret := syscall(SYS_recvfrom, sock, raw_data(buf), len(buf), transmute(i32) flags, addr, size_of(T))
+    return errno_unwrap(ret, int)
+}
+
+@private
+recv_noaddr :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg) -> (int, Errno) {
+    ret := syscall(SYS_recvfrom, sock, raw_data(buf), len(buf), transmute(i32) flags, cast(rawptr) nil, cast(uintptr) 0)
+    return errno_unwrap(ret, int)
+}
+
+sendto :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg, addr: ^$T) -> (int, Errno)
+where
+    T == Sock_Addr_In ||
+    T == Sock_Addr_In6 ||
+    T == Sock_Addr_Any
+{
+    ret := syscall(SYS_sendto, sock, raw_data(buf), len(buf), transmute(i32) flags, addr, size_of(T))
+    return errno_unwrap(ret, int)
+}
+
+@private
+send_noaddr :: proc "contextless" (sock: Fd, buf: []u8, flags: Socket_Msg) -> (int, Errno) {
+    ret := syscall(SYS_sendto, sock, raw_data(buf), len(buf), transmute(i32) flags, cast(rawptr) nil, cast(uintptr) 0)
+    return errno_unwrap(ret, int)
+}
+
+/// Receive a message from a socket
+/// Available since Linux 2.0
+recv :: proc {recvfrom, recv_noaddr}
+
+/// Send a message through a socket
+/// Available since Linux 2.0
+send :: proc {sendto, send_noaddr}
+
+// TODO(flysand): sendmsg
+
+// TODO(flysand): recvmsg
+
+shutdown :: proc "contextless" (sock: Fd, how: Shutdown_How) -> (Errno) {
+    ret := syscall(SYS_shutdown, sock, how)
+    return Errno(-ret)
+}
+
+/// Bind a socket to the given local address
+/// Available since Linux 2.0
+bind :: proc "contextless" (sock: Fd, addr: ^$T) -> (Errno)
+where
+    T == Sock_Addr_In ||
+    T == Sock_Addr_In6 ||
+    T == Sock_Addr_Any
+{
+    ret := syscall(SYS_bind, sock, addr, size_of(T))
+    return Errno(-ret)
+}
+
+/// Marks the socket as a socket that listen to connections using accept.2
+/// Available since Linux 2.0
+listen :: proc "contextless" (sock: Fd, queue_len: i32) -> (Errno) {
+    ret := syscall(SYS_listen, sock, queue_len)
+    return Errno(-ret)
+}
+
+// TODO(flysand): getsockname
+
+// TODO(flysand): getpeername
+
+// TODO(flysand): socketpair
+
+// TODO(flysand): the parameters are the same, maybe there's a way to make it into a single proc, sacrificing type
+// safety slightly
+// TODO(flysand): add ability to specify slices
+setsockopt_base :: proc "contextless" (sock: Fd, level: int, opt: int, val: $T) -> (Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    val_data := val
+    val_size := size_of(intrinsics.type_elem_type(T))
+    ret := syscall(SYS_setsockopt, sock, level, opt, val_data, val_size)
+    return Errno(-ret)
+}
+
+setsockopt_sock :: proc "contextless" (sock: Fd, level: Socket_API_Level_Sock, opt: Socket_Option, val: $T) -> (Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return setsockopt_base(sock, cast(int) level, cast(int) opt, val) 
+}
+
+setsockopt_tcp :: proc "contextless" (sock: Fd, level: Socket_API_Level_TCP, opt: Socket_TCP_Option, val: $T) -> (Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return setsockopt_base(sock, cast(int) level, cast(int) opt, val)
+}
+
+setsockopt_udp :: proc "contextless" (sock: Fd, level: Socket_API_Level_UDP, opt: Socket_UDP_Option, val: $T) -> (Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return setsockopt_base(sock, cast(int) level, cast(int) opt, val)
+}
+
+/// Set socket option for a given socket API level
+/// Available since Linux 2.0
+setsockopt :: proc {
+    setsockopt_sock,
+    setsockopt_tcp,
+    setsockopt_udp,
+    setsockopt_base,
+}
+
+getsockopt_base :: proc "contextless" (sock: Fd, level: int, opt: Socket_Option, val: $T) -> (int, Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    val_data := val
+    val_size := size_of(T)
+    ret := syscall(SYS_getsockopt, sock, level, opt, val_data, cast(rawptr) &val_size)
+    return val_size, Errno(-ret)
+}
+
+getsockopt_sock :: proc "contextless" (sock: Fd, level: Socket_API_Level_Sock, opt: Socket_Option, val: ^$T) -> (int, Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return getsockopt_base(sock, cast(int) level, cast(int) opt, val)
+}
+
+getsockopt_tcp :: proc "contextless" (sock: Fd, level: Socket_API_Level_TCP, opt: Socket_TCP_Option, val: ^$T) -> (int, Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return getsockopt_base(sock, cast(int) level, cast(int) opt, val)
+}
+
+getsockopt_udp :: proc "contextless" (sock: Fd, level: Socket_API_Level_UDP, opt: Socket_UDP_Option, val: ^$T) -> (int, Errno)
+where
+    intrinsics.type_is_pointer(T) ||
+    intrinsics.type_is_multi_pointer(T)
+{
+    return getsockopt_base(sock, cast(int) level, cast(int) opt, val)
+}
+
+/// Get socket option for a given socket API level
+/// Available since Linux 2.0
+getsockopt :: proc {
+    getsockopt_sock,
+    getsockopt_tcp,
+    getsockopt_udp,
+    getsockopt_base,
+}
+
+// TODO(flysand): clone (probably not in this PR, maybe not ever)
+
+/// Creates a copy of the running process
+/// Available since Linux 1.0
+fork :: proc "contextless" () -> (Pid, Errno) {
+    when ODIN_ARCH == .arm64 {
+        // Note(flysand): this syscall is not documented, but the bottom 8 bits of flags
+        // are for exit signal
+        ret := syscall(SYS_clone, Signal.SIGCHLD)
+        return errno_unwrap(ret, Pid)
+    } else {
+        ret := syscall(SYS_fork)
+        return errno_unwrap(ret, Pid)
+    }
+}
+
+// TODO(flysand): vfork
+
+// TODO(flysand): execve
+
+/// Exit the thread with a given exit code
+/// Available since Linux 1.0
+exit :: proc "contextless" (code: i32) -> ! {
+    syscall(SYS_exit, code)
+    unreachable()
+}
+
+/// Wait for the process to change state
+/// Available since Linux 1.0
+wait4 :: proc "contextless" (pid: Pid, status: ^u32, options: Wait_Options) -> (Pid, Errno) {
+    ret := syscall(SYS_wait4, pid, status, transmute(u32) options)
+    return errno_unwrap(ret, Pid)
+}
+
+/// See wait4
+waitpid :: wait4
+
+// TODO(flysand): kill
+
+/// Get system information
+/// Available since Linux 1.0
+uname :: proc "contextless" (uts_name: ^UTS_Name) -> (Errno) {
+    ret := syscall(SYS_uname, uts_name)
+    return Errno(-ret)
+}
+
+// TODO(flysand): semget
+
+// TODO(flysand): semop
+
+// TODO(flysand): semctl
+
+// TODO(flysand): shmdt
+
+// TODO(flysand): msgget
+
+// TODO(flysand): msgsnd
+
+// TODO(flysand): msgrcv
+
+// TODO(flysand): msgctl
+
+fcntl_dupfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_DUPFD, newfd: Fd) -> (Fd, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, newfd)
+    return errno_unwrap(ret, Fd)
+}
+
+fcntl_dupfd_cloexec :: proc "contextless" (fd: Fd, cmd: FCntl_Command_DUPFD_CLOEXEC, newfd: Fd) -> (Fd, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, newfd)
+    return errno_unwrap(ret, Fd)
+}
+
+fcntl_getfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETFD) -> (Fd, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(ret, Fd)
+}
+
+fcntl_setfd :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETFD, newfd: Fd) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, newfd)
+    return Errno(-ret)
+}
+
+fcntl_getfl :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETFL) -> (Open_Flags, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(u32(ret), Open_Flags, Open_Flags)
+}
+
+fcntl_setfl :: proc "contextless" (fd: Fd, cmd:  FCntl_Command_SETFL, flags: Open_Flags) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, transmute(u32) flags)
+    return Errno(-ret)
+}
+
+fcntl_setlk :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLK, lock: ^FLock) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_fcntl64, fd, cmd, lock)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fcntl, fd, cmd, lock)
+        return Errno(-ret)
+    }
+}
+
+fcntl_setlkw :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLKW, lock: ^FLock) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_fcntl64, fd, cmd, lock)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fcntl, fd, cmd, lock)
+        return Errno(-ret)
+    }
+}
+
+fcntl_getlk :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETLK, lock: ^FLock) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_fcntl64, fd, cmd, lock)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fcntl, fd, cmd, lock)
+        return Errno(-ret)
+    }
+}
+
+fcntl_getown_ex :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETOWN_EX, owner: ^F_Owner) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, owner)
+    return Errno(-ret)
+}
+
+fcntl_setown_ex :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETOWN_EX, owner: ^F_Owner) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, owner)
+    return Errno(-ret)
+}
+
+fcntl_getsig :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETSIG) -> (Signal, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(ret, Signal)
+}
+
+fcntl_setsig :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETSIG, sig: Signal) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, sig)
+    return Errno(-ret)
+}
+
+fcntl_setlease :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETLEASE, lease: FD_Lease) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, lease)
+    return Errno(-ret)
+}
+
+fcntl_getlease :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETLEASE) -> (FD_Lease, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(ret, FD_Lease)
+}
+
+fcntl_notify :: proc "contextless" (fd: Fd, cmd: FCntl_Command_NOTIFY, notifications: FD_Notifications) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return Errno(-ret)
+}
+
+fcntl_setpipe_sz :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SETPIPE_SZ, sz: i32) -> (i32, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, sz)
+    return errno_unwrap(ret, i32)
+}
+
+fcntl_getpipe_sz :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GETPIPE_SZ) -> (i32, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(ret, i32)
+}
+
+fcntl_add_seals :: proc "contextless" (fd: Fd, cmd: FCntl_Command_ADD_SEALS, seal: Seal) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, transmute(i32) seal)
+    return Errno(-ret)
+}
+
+fcntl_get_seals :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_SEALS) -> (Seal, Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd)
+    return errno_unwrap(i32(ret), Seal, Seal)
+}
+
+fcntl_get_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_RW_HINT, hint: ^RW_Hint) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, hint)
+    return Errno(-ret)
+}
+
+fcntl_set_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SET_RW_HINT, hint: ^RW_Hint) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, hint)
+    return Errno(-ret)
+}
+
+fcntl_get_file_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_GET_FILE_RW_HINT, hint: ^RW_Hint) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, hint)
+    return Errno(-ret)
+}
+
+fcntl_set_file_rw_hint :: proc "contextless" (fd: Fd, cmd: FCntl_Command_SET_FILE_RW_HINT, hint: ^RW_Hint) -> (Errno) {
+    ret := syscall(SYS_fcntl, fd, cmd, hint)
+    return Errno(-ret)
+}
+
+fcntl :: proc {
+    fcntl_dupfd,
+    fcntl_dupfd_cloexec,
+    fcntl_getfd,
+    fcntl_setfd,
+    fcntl_getfl,
+    fcntl_setfl,
+    fcntl_setlk,
+    fcntl_setlkw,
+    fcntl_getlk,
+    fcntl_getown_ex,
+    fcntl_setown_ex,
+    fcntl_getsig,
+    fcntl_setsig,
+    fcntl_setlease,
+    fcntl_getlease,
+    fcntl_notify,
+    fcntl_setpipe_sz,
+    fcntl_getpipe_sz,
+    fcntl_add_seals,
+    fcntl_get_seals,
+    fcntl_get_rw_hint,
+    fcntl_set_rw_hint,
+    fcntl_get_file_rw_hint,
+    fcntl_set_file_rw_hint,
+}
+
+// TODO(flysand): flock
+
+/// Sync state of the file with the storage device
+fsync :: proc "contextless" (fd: Fd) -> (Errno) {
+    ret := syscall(SYS_fsync, fd)
+    return Errno(-ret)
+}
+
+// TODO(flysand): fdatasync
+
+/// Truncate a file to specified length
+/// On 32-bit architectures available since Linux 2.4
+truncate :: proc "contextless" (name: cstring, length: i64) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_truncate64, cast(rawptr) name, compat64_arg_pair(length))
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_truncate, cast(rawptr) name, compat64_arg_pair(length))
+        return Errno(-ret)
+    }
+}
+
+/// Truncate a file specified by file descriptor to specified length
+/// On 32-bit architectures available since 2.4
+ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_truncate, fd, compat64_arg_pair(length))
+        return Errno(-ret)
+    }
+}
+
+/// Retrieve the contents of the directory specified by dirfd
+/// Returns the number of bytes written
+/// Available since Linux 2.4
+getdents :: proc "contextless" (dirfd: Fd, buf: []u8) -> (int, Errno) {
+    ret := syscall(SYS_getdents64, dirfd, raw_data(buf), len(buf))
+    return errno_unwrap(ret, int)
+}
+
+/// Get current working directory
+/// Available since Linux 1.0
+getcwd :: proc "contextless" (buf: []u8) -> (int, Errno) {
+    ret := syscall(SYS_getcwd, raw_data(buf), len(buf))
+    return errno_unwrap(ret, int)
+}
+
+/// Change working directory to the directory specified by path
+/// Available since Linux 1.0
+chdir :: proc "contextless" (path: cstring) -> (Errno) {
+    ret := syscall(SYS_chdir, cast(rawptr) path)
+    return Errno(-ret)
+}
+
+/// Change working directory to the directory specified by dirfd
+/// Available since Linux 1.0
+fchdir :: proc "contextless" (fd: Fd) -> (Errno) {
+    ret := syscall(SYS_fchdir, fd)
+    return Errno(-ret)
+}
+
+/// Rename (move) the file
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+rename :: proc "contextless" (old: cstring, new: cstring) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_renameat, AT_FDCWD, cast(rawptr) old, AT_FDCWD, cast(rawptr) new)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_rename, cast(rawptr) old, cast(rawptr) new)
+        return Errno(-ret)
+    }
+}
+
+/// Creates a directory
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+mkdir :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_mkdirat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_mkdir, cast(rawptr) name, transmute(u32) mode)
+        return Errno(-ret)
+    }
+}
+
+/// Remove a directory specified by name
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+rmdir :: proc "contextless" (name: cstring) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, transmute(i32) FD_Flags{.REMOVEDIR})
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_rmdir, cast(rawptr) name)
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): creat
+
+/// Create a hard link on a file
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_link, cast(rawptr) target, cast(rawptr) linkpath)
+        return Errno(-ret)
+    }
+}
+
+/// Delete a name, and possible a file it refers to
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+unlink :: proc "contextless" (name: cstring) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_unlinkat, AT_FDCWD, cast(rawptr) name, 0)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_unlink, cast(rawptr) name)
+        return Errno(-ret)
+    }
+}
+
+/// Create a symbolic link
+/// Available since Linux 1.0
+/// On arm64 available since Linux 2.6.16
+symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_symlinkat, AT_FDCWD, cast(rawptr) target, cast(rawptr) linkpath)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_symlink, cast(rawptr) target, cast(rawptr) linkpath)
+        return Errno(-ret)
+    }
+}
+
+/// Read the value of a symbolic link
+/// Available since Linux 1.0
+/// On arm64 available since Linux 2.6.16
+readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_readlinkat, AT_FDCWD, cast(rawptr) name, raw_data(buf), len(buf))
+        return errno_unwrap(ret, int)
+    } else {
+        ret := syscall(SYS_readlink, cast(rawptr) name, raw_data(buf), len(buf))
+        return errno_unwrap(ret, int)
+    }
+}
+
+/// Change file permissions
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, 0)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_chmod, cast(rawptr) name, transmute(u32) mode)
+        return Errno(-ret)
+    }
+}
+
+/// Change file permissions through a file descriptor
+/// Available since Linux 1.0
+fchmod :: proc "contextless" (fd: Fd, mode: Mode) -> (Errno) {
+    ret := syscall(SYS_fchmod, fd, transmute(u32) mode)
+    return Errno(-ret)
+}
+
+/// Change ownership of a file
+/// Available since Linux 2.2
+/// On 32-bit architectures available since Linux 2.4
+/// On ARM64 available since Linux 2.6.16
+chown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_chown32, cast(rawptr) name, uid, gid)
+        return Errno(-ret)
+    } else when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, 0)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_chown, cast(rawptr) name, uid, gid)
+        return Errno(-ret)
+    }
+}
+
+/// Change ownership of a file by file descriptor
+/// Available since Linux 1.0
+/// On 32-bit architecvtures available since Linux 2.4
+fchown :: proc "contextless" (fd: Fd, uid: Uid, gid: Gid) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_fchown32, fd, uid, gid)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fchown, fd, uid, gid)
+        return Errno(-ret)
+    }
+}
+
+/// Change ownership of a file. Unlike chown, if a file is a symlink dooesn't dereference it
+/// Available since Linux 1.0
+/// On 32-bit architectures available since Linux 2.4
+/// On ARM64 available since Linux 2.6.16
+lchown :: proc "contextless" (name: cstring, uid: Uid, gid: Gid) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_lchown32, cast(rawptr) name, uid, gid)
+        return Errno(-ret)
+    } else when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_fchownat, AT_FDCWD, cast(rawptr) name, uid, gid, transmute(i32) FD_Flags{.SYMLINK_NOFOLLOW})
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_lchown, cast(rawptr) name, uid, gid)
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): umask
+
+// TODO(flysand): gettimeofday
+
+/// Get limits on resources
+/// Available since Linux 1.0
+getrlimit :: proc "contextless" (kind: RLimit_Kind, resource: ^RLimit) -> (Errno) {
+    ret := syscall(SYS_getrlimit, kind, resource)
+    return Errno(-ret)
+}
+
+/// Get resource usage
+/// Available since Linux 1.0
+getrusage :: proc "contextless" (who: RUsage_Who, rusage: ^RUsage) -> (Errno) {
+    ret := syscall(SYS_getrusage, who, rusage)
+    return Errno(-ret)
+}
+
+/// Get information about the system
+sysinfo :: proc "contextless" (sysinfo: ^Sys_Info) -> (Errno) {
+    ret := syscall(SYS_sysinfo, sysinfo)
+    return Errno(-ret)
+}
+
+/// Get current process times
+/// Available since Linux 1.0
+times :: proc "contextless" (tms: ^Tms) -> (Errno) {
+    ret := syscall(SYS_times, cast(rawptr) tms)
+    return Errno(-ret)
+}
+
+// TODO(flysand): ptrace
+
+/// Get real user ID
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+getuid :: proc "contextless" () -> Uid {
+    when size_of(int) == 8 {
+        return cast(Uid) syscall(SYS_getuid)
+    } else {
+        return cast(Uid) syscall(SYS_getuid32)
+    }
+}
+
+// TODO(flysand): syslog
+
+/// Get real group ID
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+getgid :: proc "contextless" () -> Gid {
+    when size_of(int) == 8 {
+        return cast(Gid) syscall(SYS_getgid)
+    } else {
+        return cast(Gid) syscall(SYS_getgid32)
+    }
+}
+
+/// Set effective user id
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setuid :: proc "contextless" (uid: Uid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setuid, uid)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setuid32, uid)
+        return Errno(-ret)
+    }
+}
+
+/// Set effective group id
+/// If the process is privileged also sets real group id
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setgid :: proc "contextless" (gid: Gid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setgid, gid)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setgid32, gid)
+        return Errno(-ret)
+    }
+}
+
+/// Get effective user ID
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+geteuid :: proc "contextless" () -> Uid {
+    when size_of(int) == 8 {
+        return cast(Uid) syscall(SYS_geteuid)
+    } else {
+        return cast(Uid) syscall(SYS_geteuid32)
+    }
+}
+
+/// Get effective group ID
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+getegid :: proc "contextless" () -> Gid {
+    when size_of(int) == 8 {
+        return cast(Gid) syscall(SYS_getegid)
+    } else {
+        return cast(Gid) syscall(SYS_getegid32)
+    }
+}
+
+/// Set process group
+/// Available since Linux 1.0
+setpgid :: proc "contextless" (pid: Pid, pgid: Pid) -> (Errno) {
+    ret := syscall(SYS_setpgid, pid, pgid)
+    return Errno(-ret)
+}
+
+/// Get the parent process ID
+/// Available since Linux 1.0
+getppid :: proc "contextless" () -> Pid {
+    return cast(Pid) syscall(SYS_getppid)
+}
+
+/// Get process group
+/// Available since Linux 1.0
+getpgrp :: proc "contextless" () -> (Pid, Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_getpgid, 0)
+        return errno_unwrap(ret, Pid)
+    } else {
+        ret := syscall(SYS_getpgrp)
+        return errno_unwrap(ret, Pid)
+    }
+}
+
+/// Create a session and set the process group ID
+/// Available since Linux 2.0
+setsid :: proc "contextless" () -> (Errno) {
+    ret := syscall(SYS_setsid)
+    return Errno(-ret)
+}
+
+/// Set real and/or effective user id
+/// If any of the arguments is -1, the corresponding id is not changed
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setreuid :: proc "contextless" (real: Uid, effective: Uid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setreuid, real, effective)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setreuid32, real, effective)
+        return Errno(-ret)
+    }
+}
+
+/// Set real and/or effective group id
+/// If any of the arguments is -1, the corresponding id is not changed
+/// Available since Linux 1.0
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setregid :: proc "contextless" (real: Gid, effective: Gid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setregid, real, effective)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setregid32, real, effective)
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): getgroups
+
+// TODO(flysand): setgroups
+
+/// Set real, effective and/or saved user id
+/// If any of the arguments is -1, the corresponding id is not changed
+/// Available since Linux 2.2
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setresuid :: proc "contextless" (real: Uid, effective: Uid, saved: Uid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setresuid, real, effective, saved)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setresuid32, real, effective, saved)
+        return Errno(-ret)
+    }
+}
+
+/// Get real, effective and saved user id
+/// Available since Linux 2.2
+/// On 32-bit platforms available since Linux 2.4
+getresuid :: proc "contextless" (real: ^Uid, effective: ^Uid, saved: ^Uid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_getresuid, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_getresuid32, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved)
+        return Errno(-ret)
+    }
+}
+
+/// Set real, effective and/or saved group id
+/// If any of the arguments is -1, the corresponding id is not changed
+/// Available since Linux 2.2
+/// On 32-bit platforms available since Linux 2.4
+@(require_results)
+setresgid :: proc "contextless" (real: Gid, effective: Gid, saved: Uid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_setresgid, real, effective, saved)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_setresgid32, real, effective, saved)
+        return Errno(-ret)
+    }
+}
+
+/// Get real, effective and saved group id
+/// Available since Linux 2.2
+/// On 32-bit platforms available since Linux 2.4
+getresgid :: proc "contextless" (real: ^Gid, effective: ^Gid, saved: ^Gid) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_getresgid, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_getresgid32, cast(rawptr) real, cast(rawptr) effective, cast(rawptr) saved)
+        return Errno(-ret)
+    }
+}
+
+/// Get process group
+/// Available since Linux 1.0
+getpgid :: proc "contextless" (pid: Pid) -> (Pid, Errno) {
+    ret := syscall(SYS_getpgid, pid)
+    return errno_unwrap(ret, Pid)
+}
+
+// NOTE(flysand): setfsuid and setfsgid are deprecated
+
+/// Get session ID of the calling process
+/// Available since Linux 2.0
+getsid :: proc "contextless" (pid: Pid) -> (Pid, Errno) {
+    ret := syscall(SYS_getsid, pid)
+    return errno_unwrap(ret, Pid)
+}
+
+// TODO(flysand): capget
+
+// TODO(flysand): capset
+
+/// Examine pending signals
+/// Available since Linux 2.2
+rt_sigpending :: proc "contextless" (sigs: ^Sig_Set) -> Errno {
+    ret := syscall(SYS_rt_sigpending, sigs, size_of(Sig_Set))
+    return Errno(-ret)
+}
+
+/// Synchronously wait for queued signals
+/// Available since Linux 2.2
+rt_sigtimedwait :: proc "contextless" (sigs: ^Sig_Set, info: ^Sig_Info, time_sus: ^Time_Spec) -> (Signal, Errno) {
+    ret := syscall(SYS_rt_sigtimedwait, sigs, info, time_sus, size_of(Sig_Set))
+    return errno_unwrap(ret, Signal)
+}
+
+/// Send signal information to a process
+/// Available since Linux 2.2
+rt_sigqueueinfo :: proc "contextless" (pid: Pid, sig: Signal, si: ^Sig_Info) -> (Errno) {
+    ret := syscall(SYS_rt_sigqueueinfo, pid, sig, si)
+    return Errno(-ret)
+}
+
+/// Replace the signal mask for a value with the new mask until a signal is received
+/// Available since Linux 2.2
+rt_sigsuspend :: proc "contextless" (sigset: ^Sig_Set) -> Errno {
+    ret := syscall(SYS_rt_sigsuspend, sigset, size_of(Sig_Set))
+    return Errno(-ret)
+}
+
+/// Set or get signal stack context
+/// Available since Linux 2.2
+sigaltstack :: proc "contextless" (stack: ^Sig_Stack, old_stack: ^Sig_Stack) -> (Errno) {
+    ret := syscall(SYS_sigaltstack, stack, old_stack)
+    return Errno(-ret)
+}
+
+// TODO(flysand): utime
+
+/// Create a special or ordinary file
+/// `mode` parameter contains both the the file mode and the type of the node to create
+///  ->  Add one of S_IFSOCK, S_IFBLK, S_IFFIFO, S_IFCHR to mode
+/// Available since Linux 1.0
+/// On ARM64 available since Linux 2.6.16
+mknod :: proc "contextless" (name: cstring, mode: Mode, dev: Dev) -> (Errno) {
+    when ODIN_ARCH == .arm64 {
+        ret := syscall(SYS_mknodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode, dev)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_mknod, cast(rawptr) name, transmute(u32) mode, dev)
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): uselib
+
+/// Set the process execution domain
+/// Available since Linux 1.2
+personality :: proc "contextless" (personality: uint) -> (uint, Errno) {
+    ret := syscall(SYS_personality, personality)
+    return errno_unwrap(ret, uint)
+}
+
+// TODO(flysand): ustat
+
+/// Query information about filesystem
+///
+/// Available since Linux 1.0
+/// For 32-bit systems a different syscall is used that became available since 2.6
+statfs :: proc "contextless" (path: cstring, statfs: ^Stat_FS) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_statfs, transmute(uintptr) path, statfs)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_statfs64, cast(rawptr) path, size_of(Stat_FS), statfs)
+        return Errno(-ret)
+    }
+}
+
+/// Query information about filesystem by file descriptor
+///
+/// Available since Linux 1.0
+/// For 32-bit systems a different syscall is used that became available since 2.6
+fstatfs :: proc "contextless" (fd: Fd, statfs: ^Stat_FS) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_statfs, fd, statfs)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_statfs64, fd, size_of(Stat_FS), statfs)
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): sysfs
+
+/// Get priority on user, process group or process
+/// Available since Linux 1.0
+getpriority :: proc "contextless" (which: Priority_Which, who: i32) -> (i32, Errno) {
+    ret := syscall(SYS_getpriority, which, who)
+    prio, err := errno_unwrap(ret, i32)
+    // NOTE(flysand): getpriority will return `20 - priority` to avoid returning
+    // negative priorities as errors
+    prio = 20 - prio
+    return prio, err
+}
+
+/// Set priority on user, process group or process
+/// Available since Linux 1.0
+setpriority :: proc "contextless" (which: Priority_Which, who: i32, prio: i32) -> (Errno) {
+    ret := syscall(SYS_setpriority, which, who, prio)
+    return Errno(-ret)
+}
+
+// TODO(flysand): sched_setparam
+
+// TODO(flysand): sched_getparam
+
+// TODO(flysand): sched_setscheduler
+
+// TODO(flysand): sched_getscheduler
+
+// TODO(flysand): sched_get_priority_max
+
+// TODO(flysand): sched_get_priority_min
+
+// TODO(flysand): sched_rr_get_interval
+
+/// Lock and memory
+/// Available since Linux 2.0
+/// If flags specified, available since Linux 4.4
+mlock :: proc "contextless" (addr: rawptr, size: uint, flags: MLock_Flags = {}) -> (Errno) {
+    // Pretty darn recent syscall, better call simpler version if we can
+    if flags > {} {
+        ret := syscall(SYS_mlock2, addr, size, transmute(i32) flags)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_mlock, addr, size)
+        return Errno(-ret)
+    }
+}
+
+/// Unlock memory
+/// Available since Linux 2.0
+munlock :: proc "contextless" (addr: rawptr, size: uint) -> (Errno) {
+    ret := syscall(SYS_munlock, addr, size)
+    return Errno(-ret)
+}
+
+/// Lock all memory
+mlockall :: proc "contextless" (flags: MLock_Flags = {}) -> (Errno) {
+    ret := syscall(SYS_mlockall, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+/// Unlock all memory
+munlockall :: proc "contextless" () -> (Errno) {
+    ret := syscall(SYS_munlockall)
+    return Errno(-ret)
+}
+
+// TODO(flysand): vhangup
+
+// TODO(flysand): modify_ldt
+
+// TODO(flysand): pivot_root
+
+// TODO(flysand): _sysctl
+
+// TODO(flysand): prctl
+
+// TODO(flysand): arch_prctl
+
+// TODO(flysand): adj_timex
+
+/// Set limits on resources
+/// Available since Linux 1.0
+setrlimit :: proc "contextless" (kind: RLimit_Kind, resource: ^RLimit) -> (Errno) {
+    ret := syscall(SYS_setrlimit, kind, resource)
+    return Errno(-ret)
+}
+
+// TODO(flysand): sync
+
+// TODO(flysand): acct
+
+// TODO(flysand): settimeofday
+
+// TODO(flysand): mount
+
+// TODO(flysand): umount2
+
+// TODO(flysand): swapon
+
+// TODO(flysand): swapoff
+
+// TODO(flysand): reboot
+
+/// Set hostname
+/// Note: to get the host name, use `uname` syscall
+/// Available since Linux 1.0
+sethostname :: proc "contextless" (hostname: string) -> (Errno) {
+    ret := syscall(SYS_sethostname, raw_data(hostname), len(hostname))
+    return Errno(-ret)
+}
+
+/// Set domain name
+/// Note: to get the domain name, use `uname` syscall
+/// Available since Linux 2.2
+setdomainname :: proc "contextless" (name: string) -> (Errno) {
+    ret := syscall(SYS_setdomainname, raw_data(name), len(name))
+    return Errno(-ret)
+}
+
+// TODO(flysand): iopl
+
+// TODO(flysand): ioperm
+
+// TODO(flysand): create_module
+
+// TODO(flysand): init_module
+
+// TODO(flysand): delete_module
+
+// TODO(flysand): get_kernel_syms
+
+// TODO(flysand): query_module
+
+// TODO(flysand): quotactl
+
+// TODO(flysand): nfsservctl
+
+// TODO(flysand): getpmsg
+
+// TODO(flysand): putpmsg
+
+// TODO(flysand): afs_syscall
+
+// TODO(flysand): tuxcall
+
+// TODO(flysand): security
+
+/// Returns the thread ID of the current process
+/// This is what the kernel calls "pid"
+/// Let me insert a tiny rant here, this terminology is confusing:
+/// sometimes pid refers to a thread, and other times it refers
+/// to a thread group (process group?)
+/// Anyway, this syscall is available since Linux 1.0
+gettid :: proc "contextless" () -> Pid {
+    return cast(Pid) syscall(SYS_gettid)
+}
+
+// TODO(flysand): readahead
+
+// TODO(flysand): setxattr
+
+// TODO(flysand): lsetxattr
+
+// TODO(flysand): fsetxattr
+
+// TODO(flysand): getxattr
+
+// TODO(flysand): lgetxattr
+
+// TODO(flysand): fgetxattr
+
+// TODO(flysand): listxattr
+
+// TODO(flysand): llistxattr
+
+// TODO(flysand): flistxattr
+
+// TODO(flysand): removexattr
+
+// TODO(flysand): lremovexattr
+
+// TODO(flysand): fremovexattr
+
+// TODO(flysand): tkill
+
+// TODO(flysand): time
+
+/// Wait on a futex until it's signaled
+futex_wait :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Type, flags: Futex_Flags, val: u32, timeout: ^Time_Spec = nil) -> (Errno) {
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, val, timeout)
+    return Errno(-ret)
+}
+
+/// Wake up other threads on a futex
+///  n_wakeup specifies the number of processes to wakeup. Specify max(i32) to wake up all processes waiting
+futex_wake :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Type, flags: Futex_Flags, n_wakeup: i32) -> (int, Errno) {
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, n_wakeup)
+    return errno_unwrap(ret, int)
+}
+
+// NOTE(flysand): futex_fd is racy, so not implemented
+
+/// Requeues processes waiting on futex `futex` to wait on futex `requeue_futex`
+/// `requeue_threshold` specifies the maximum amount of waiters to wake up, the rest of the waiters will be requeued
+/// `requeue_max` specifies the maximum amount of waiters that are required at `requeue_futex`
+/// The operation blocks until the `requeue_max` requirement is satisfied
+/// If the value of the mutex is not equal to `val`, fails with EAGAIN before any further checks
+/// Returns the total number of waiters that have been woken up plus the number of waiters requeued
+futex_cmp_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Cmp_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32,
+    requeue_max: i32, requeue_futex: ^Futex, val: i32) -> (int, Errno)
+{
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex, val)
+    return errno_unwrap(ret, int)
+}
+
+/// See `futex_cmp_requeue`, this function does the same thing but doesn't check the value of the futex
+/// Returns the total number of waiters that have been woken up
+futex_requeue :: proc "contextless" (futex: ^Futex, op: Futex_Requeue_Type, flags: Futex_Flags, requeue_threshold: u32,
+    requeue_max: i32, requeue_futex: ^Futex) -> (int, Errno)
+{
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, requeue_threshold, requeue_max, requeue_futex)
+    return errno_unwrap(ret, int)
+}
+
+/// Okay, for this one, see the man pages, the description for it is pretty long and very specific. It's sole
+/// purpose is to allow implementing conditional values sync primitive, it seems like
+futex_wake_op :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Op_Type, flags: Futex_Flags, wakeup: i32,
+    dst_wakeup, dst: ^Futex, futex_op: u32) -> (int, Errno)
+{
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, wakeup, dst_wakeup, dst, futex_op)
+    return errno_unwrap(ret, int)
+}
+
+/// Same as wait, but mask specifies bits that must be equal for the mutex to wake up
+futex_wait_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wait_Bitset_Type, flags: Futex_Flags, val: u32,
+    timeout: ^Time_Spec, mask: u32) -> (int, Errno)
+{
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, val, timeout, 0, mask)
+    return errno_unwrap(ret, int)
+}
+
+/// Wake up on bitset
+futex_wake_bitset :: proc "contextless" (futex: ^Futex, op: Futex_Wake_Bitset_Type, flags: Futex_Flags, n_wakeup: u32, mask: u32) -> (int, Errno)
+{
+    futex_flags := cast(u32) op + transmute(u32) flags
+    ret := syscall(SYS_futex, futex, futex_flags, n_wakeup, 0, 0, mask)
+    return errno_unwrap(ret, int)
+}
+
+// TODO(flysand): Priority inheritance (PI) futicees
+
+futex :: proc {
+    futex_wait,
+    futex_wake,
+    futex_cmp_requeue,
+    futex_requeue,
+    futex_wake_op,
+    futex_wait_bitset,
+    futex_wake_bitset,
+}
+
+// TODO(flysand): sched_setaffinity
+
+// TODO(flysand): sched_getaffinity
+
+// TODO(flysand): set_thread_area
+
+// TODO(flysand): io_setup
+
+// TODO(flysand): io_destroy
+
+// TODO(flysand): io_getevents
+
+// TODO(flysand): io_submit
+
+// TODO(flysand): io_cancel
+
+// TODO(flysand): get_thread_area
+
+// TODO(flysand): lookup_dcookie
+
+// TODO(flysand): epoll_create
+
+// TODO(flysand): epoll_ctl_old
+
+// TODO(flysand): epoll_wait_old
+
+// TODO(flysand): remap_file_pages
+
+/// Set the address of the futex that's gonna be waken when
+/// current thread terminates
+/// Available since Linux 2.6
+set_tid_address :: proc "contextless" (tidptr: ^u32) {
+    syscall(SYS_set_tid_address, tidptr)
+}
+
+// TODO(flysand): restart_syscall
+
+// TODO(flysand): semtimedop
+
+// TODO(flysand): fadvise64
+
+// TODO(flysand): timer_create
+
+// TODO(flysand): timer_settime
+
+// TODO(flysand): timer_gettime
+
+// TODO(flysand): timer_getoverrun
+
+// TODO(flysand): timer_delete
+
+// TODO(flysand): clock_settime
+
+// TODO(flysand): clock_gettime
+
+// TODO(flysand): clock_getres
+
+// TODO(flysand): clock_nanosleep
+
+/// Exit the thread group
+/// Available since Linux 2.6
+exit_group :: proc "contextless" (code: i32) -> ! {
+    syscall(SYS_exit_group, code)
+    unreachable()
+}
+
+// TODO(flysand): epoll_wait
+
+// TODO(flysand): epoll_ctl
+
+// TODO(flysand): tgkill
+
+// TODO(flysand): utimes
+
+// TODO(flysand): vserver
+
+// TODO(flysand): mbind
+
+// TODO(flysand): set_mempolicy
+
+// TODO(flysand): get_mempolicy
+
+// TODO(flysand): mq_open
+
+// TODO(flysand): mq_unlink
+
+// TODO(flysand): mq_timedsend
+
+// TODO(flysand): mq_timedreceive
+
+// TODO(flysand): mq_notify
+
+// TODO(flysand): mq_getsetattr
+
+// TODO(flysand): kexec_load
+
+
+/// Wait on process, process group or pid file descriptor
+/// Available since Linux 2.6.10
+waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, options: Wait_Options) -> (Errno) {
+    ret := syscall(SYS_waitid, id_type, id, sig_info, transmute(i32) options)
+    return Errno(-ret)
+}
+
+// TODO(flysand): add_key
+
+// TODO(flysand): request_key
+
+// TODO(flysand): keyctl
+
+// TODO(flysand): ioprio_set
+
+// TODO(flysand): ioprio_get
+
+// TODO(flysand): inotify_init
+
+// TODO(flysand): inotify_add_watch
+
+// TODO(flysand): inotify_rm_watch
+
+// TODO(flysand): migrate_pages
+
+/// Open file at the specified file descriptor
+/// Available since Linux 2.6.16
+openat :: proc "contextless" (fd: Fd, name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) {
+    ret := syscall(SYS_openat, fd, AT_FDCWD, transmute(uintptr) name, transmute(u32) mode)
+    return errno_unwrap(ret, Fd)
+}
+
+/// Create a directory relative to specified dirfd
+/// Available since Linux 2.6.16
+mkdirat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode) -> (Errno) {
+    ret := syscall(SYS_mkdirat, dirfd, cast(rawptr) name, transmute(u32) mode)
+    return Errno(-ret)
+}
+
+/// Create a special or ordinary file wrt given directory specified by dirfd
+/// Available since Linux 2.6.16
+mknodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, dev: Dev) -> (Errno) {
+    ret := syscall(SYS_mknodat, dirfd, cast(rawptr) name, transmute(u32) mode, dev)
+    return Errno(-ret)
+}
+
+/// Change the ownership of the file specified relative to directory
+/// Available since Linux 2.6.16
+fchownat :: proc "contextless" (dirfd: Fd, name: cstring, uid: Uid, gid: Gid) -> (Errno) {
+    ret := syscall(SYS_fchownat, dirfd, cast(rawptr) name, uid, gid)
+    return Errno(-ret)
+}
+
+// TODO(flysand): futimesat
+
+/// Get information about a file at a specific directory
+/// Available since Linux 2.6.16
+fstatat :: proc "contextless" (dirfd: Fd, name: cstring, stat: ^Stat, flags: FD_Flags) -> (Errno) {
+    when size_of(int) == 4 {
+        ret := syscall(SYS_fstatat64, dirfd, cast(rawptr) name, stat, transmute(i32) flags)
+        return Errno(-ret)
+    } else when ODIN_ARCH == .amd64 {
+        ret := syscall(SYS_newfstatat, dirfd, cast(rawptr) name, stat, transmute(i32) flags)
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_fstatat, dirfd, cast(rawptr) name, stat, transmute(i32) flags)
+        return Errno(-ret)
+    }
+}
+
+/// Remove a directory entry relative to a directory file descriptor
+/// Available since Linux 2.6.16
+unlinkat :: proc "contextless" (dirfd: Fd, name: cstring, flags: FD_Flags) -> (Errno) {
+    ret := syscall(SYS_unlinkat, dirfd, cast(rawptr) name, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+/// Rename the file with names relative to the specified dirfd's
+/// Available since Linux 2.6.16
+renameat :: proc "contextless" (oldfd: Fd, old: cstring, newfd: Fd, new: cstring) -> (Errno) {
+    ret := syscall(SYS_renameat, oldfd, cast(rawptr) old, newfd, cast(rawptr) new)
+    return Errno(-ret)
+}
+
+/// Creates a hard link on a file relative to specified dirfd
+/// Available since Linux 2.6.16
+linkat :: proc "contextless" (target_dirfd: Fd, oldpath: cstring, link_dirfd: Fd, link: cstring, flags: FD_Flags) -> (Errno) {
+    ret := syscall(SYS_linkat, target_dirfd, cast(rawptr) oldpath, link_dirfd, cast(rawptr) link, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+/// Create a symbolic link at specified dirfd
+/// Available since Linux 2.6.16
+symlinkat :: proc "contextless" (dirfd: Fd, target: cstring, linkpath: cstring) -> (Errno) {
+    ret := syscall(SYS_symlinkat, dirfd, cast(rawptr) target, cast(rawptr) linkpath)
+    return Errno(-ret)
+}
+
+/// Read the value of a symbolic link at given dirfd
+/// Available since Linux 2.6.16
+readlinkat :: proc "contextless" (dirfd: Fd, name: cstring, buf: []u8) -> (int, Errno) {
+    ret := syscall(SYS_readlinkat, dirfd, cast(rawptr) name, raw_data(buf), len(buf))
+    return errno_unwrap(ret, int)
+}
+
+/// Change the file mode at a specified file descriptor
+/// Available since Linux 2.6.16
+fchmodat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode, flags: FD_Flags) -> (Errno) {
+    ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+/// Checks the user permissions for a file at specified dirfd
+/// Available since Linux 2.6.16
+faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) -> (bool, Errno) {
+    ret := syscall(SYS_faccessat, dirfd, cast(rawptr) name, transmute(u32) mode)
+    return errno_unwrap(ret, bool)
+}
+
+// TODO(flysand): pselect6
+
+/// Wait for events on a file descriptor
+/// Available since Linux 2.6.16
+ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (Errno) {
+    when size_of(int) == 8 {
+        ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
+        return Errno(-ret)
+    } else {
+        ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
+        return Errno(-ret)
+    }
+}
+
+// TODO(flysand): unshare
+
+// TODO(flysand): set_robust_list
+
+// TODO(flysand): get_robust_list
+
+// TODO(flysand): splice
+
+// TODO(flysand): tee
+
+// TODO(flysand): sync_file_range
+
+// TODO(flysand): vmsplice
+
+// TODO(flysand): move_pages
+
+/// Change file timestamps with nanosecond precision
+/// Available since Linux 2.6.22
+utimensat :: proc "contextless" (dirfd: Fd, name: cstring, timespec: ^Time_Spec, flags: FD_Flags) -> (Errno) {
+    ret := syscall(SYS_utimensat, dirfd, cast(rawptr) name, timespec, transmute(i32) flags)
+    return Errno(-ret)
+}
+
+// TODO(flysand): epoll_pwait
+
+// TODO(flysand): signalfd
+
+// TODO(flysand): timerfd_create
+
+// TODO(flysand): eventfd
+
+// TODO(flysand): fallocate
+
+// TODO(flysand): timerfd_settime
+
+// TODO(flysand): timerfd_gettime
+
+// TODO(flysand): accept4
+
+// TODO(flysand): signalfd4
+
+// TODO(flysand): eventfd2
+
+// TODO(flysand): epoll_create1
+
+/// Adjust an existing file descriptor to point to the same file as `old`
+/// In addition to dup2 allows to pass O_CLOEXEC flag
+/// Available since Linux 2.6.27
+dup3 :: proc "contextless" (old: Fd, new: Fd, flags: Open_Flags) -> (Fd, Errno) {
+    ret := syscall(SYS_dup3, old, new, transmute(i32) flags)
+    return errno_unwrap(ret, Fd)
+}
+
+// TODO(flysand): inotify_init1
+
+// TODO(flysand): preadv
+
+// TODO(flysand): pwritev
+
+
+/// Send signal information to a thread
+/// Available since Linux 2.2
+rt_tgsigqueueinfo :: proc "contextless" (tgid: Pid, pid: Pid, sig: Signal, si: ^Sig_Info) -> (Errno) {
+    ret := syscall(SYS_rt_tgsigqueueinfo, tgid, pid, sig, si)
+    return Errno(-ret)
+}
+
+/// Set up performance monitoring
+/// Available since Linux 2.6.31
+perf_event_open :: proc "contextless" (attr: ^Perf_Event_Attr, pid: Pid, cpu: int, group_fd: Fd, flags: Perf_Flags = {}) -> (Fd, Errno) {
+    ret := syscall(SYS_perf_event_open, attr, pid, cpu, group_fd, transmute(uint) flags)
+    return errno_unwrap(ret, Fd)
+}
+
+// TODO(flysand): recvmmsg
+
+// TODO(flysand): fanotify_init
+
+// TODO(flysand): fanotify_mark
+
+// TODO(flysand): prlimit64
+
+// TODO(flysand): name_to_handle_at
+
+// TODO(flysand): open_by_handle_at
+
+// TODO(flysand): clock_adjtime
+
+// TODO(flysand): syncfs
+
+// TODO(flysand): sendmmsg
+
+// TODO(flysand): setns
+
+// TODO(flysand): getcpu
+
+// TODO(flysand): process_vm_readv
+
+// TODO(flysand): process_vm_writev
+
+// TODO(flysand): kcmp
+
+// TODO(flysand): finit_module
+
+// TODO(flysand): sched_setattr
+
+// TODO(flysand): sched_getattr
+
+/// Rename the file with names relative to the specified dirfd's with other options
+/// Available since Linux 3.15
+renameat2 :: proc "contextless" (oldfd: Fd, old: cstring, newfd: Fd, new: cstring, flags: Rename_Flags) -> (Errno) {
+    ret := syscall(SYS_renameat2, oldfd, cast(rawptr) old, newfd, cast(rawptr) new, transmute(u32) flags)
+    return Errno(-ret)
+}
+
+// TODO(flysand): seccomp
+
+getrandom :: proc "contextless" (buf: []u8, flags: Get_Random_Flags) -> (int, Errno) {
+    ret := syscall(SYS_getrandom, raw_data(buf), len(buf), transmute(i32) flags)
+    return errno_unwrap(ret, int)
+}
+
+// TODO(flysand): memfd_create
+
+// TODO(flysand): kexec_file_load
+
+// TODO(flysand): bpf
+
+// TODO(flysand): execveat
+
+// TODO(flysand): userfaultfd
+
+// TODO(flysand): membarrier
+
+// TODO(flysand): mlock2
+
+// TODO(flysand): copy_file_range
+
+// TODO(flysand): preadv2
+
+// TODO(flysand): pwritev2
+
+// TODO(flysand): pkey_mprotect
+
+// TODO(flysand): pkey_alloc
+
+// TODO(flysand): pkey_free
+
+/// Query extended information about the file
+///
+/// The file can be specified as:
+///   absolute pathname: `dir` parameter is ignored
+///   relatvie pathname: `dir` parameter specifies the base directory's fd
+///   file descriptor:   `AT_EMPTY_PATH` is passed in flags, pathname is empty, `dir` specifies the file descriptor
+///
+/// Available since Linux 4.11
+statx :: proc "contextless" (dir: Fd, pathname: cstring, flags: FD_Flags, mask: Statx_Mask, statx: ^Statx) -> (Errno) {
+    ret := syscall(SYS_statx, dir, transmute(uintptr) pathname, transmute(i32) flags, transmute(u32) mask, statx)
+    return Errno(-ret)
+}
+
+// TODO(flysand): io_pgetevents
+
+// TODO(flysand): rseq
+
+// TODO(flysand): pidfd_send_signal
+
+// TODO(flysand): io_uring_setup
+
+// TODO(flysand): io_uring_enter
+
+// TODO(flysand): io_uring_register
+
+// TODO(flysand): open_tree
+
+// TODO(flysand): move_mount
+
+// TODO(flysand): fsopen
+
+// TODO(flysand): fsconfig
+
+// TODO(flysand): fsmount
+
+// TODO(flysand): fspick
+
+/// Creates a new PID file descriptor
+/// The process identified by `pid` must be a pid group leader
+/// The returned `pidfd` has `CLOEXEC` semantics
+/// Available since Linux 5.3
+pidfd_open :: proc "contextless" (pid: Pid, flags: Pid_FD_Flags) -> (Pid_FD, Errno) {
+    ret := syscall(SYS_pidfd_open, pid, transmute(i32) flags)
+    return errno_unwrap(ret, Pid_FD)
+}
+
+// TODO(flysand): clone3 (probably not this PR)
+
+/// Close the range of files as an atomic operation
+/// The range of file descriptors is inclusive, and may contain invalid file descriptors
+/// Available since Linux 5.9
+close_range :: proc "contextless" (lo: Fd, hi: Fd, flags: Close_Range_Flags) -> (Errno) {
+    ret := syscall(SYS_close_range, lo, hi, transmute(u32) flags)
+    return Errno(-ret)
+}
+
+// TODO(flysand): openat2
+
+/// Get a file descriptor from another process
+/// `fd` refers to a file descriptor number to get
+/// `flags` must be zero
+/// Available since Linux 5.3
+pidfd_getfd :: proc "contextless" (pidfd: Pid_FD, fd: Fd, flags: i32 = 0) -> (Fd, Errno) {
+    ret := syscall(SYS_pidfd_getfd, pidfd, fd, flags)
+    return errno_unwrap(ret, Fd)
+}
+
+/// Checks the user permissions for a file at specified dirfd (with flags)
+/// Available since Linux 5.8
+faccessat2 :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK, flags: FD_Flags = FD_Flags{}) -> (bool, Errno) {
+    ret := syscall(SYS_faccessat2, dirfd, cast(rawptr) name, transmute(u32) mode, transmute(i32) flags)
+    return errno_unwrap(ret, bool)
+}
+
+// TODO(flysand): process_madvise
+
+// TODO(flysand): epoll_pwait2
+
+// TODO(flysand): mount_setattr
+
+// TODO(flysand): quotactl_fd
+
+// TODO(flysand): landlock_create_ruleset
+
+// TODO(flysand): landlock_add_rule
+
+// TODO(flysand): landlock_restrict_self
+
+// TODO(flysand): memfd_secret
+
+// TODO(flysand): process_mrelease
+
+// TODO(flysand): futex_waitv
+
+// TODO(flysand): set_mempolicy_home_node
+
+// TODO(flysand): cachestat
+
+// TODO(flysand): fchmodat2
+
+// TODO(flysand): map_shadow_stack

+ 373 - 0
core/sys/linux/syscall_amd64.odin

@@ -0,0 +1,373 @@
+//+build amd64
+package linux
+
+// AMD64 uses the new way to define syscalls, i.e. one that
+// is different from the other architectures. Instead of using
+// a .tbl file, they define constants to tell which syscalls they
+// want and then include a generic unistd.h file.
+
+SYS_read                    :: uintptr(0)
+SYS_write                   :: uintptr(1)
+SYS_open                    :: uintptr(2)
+SYS_close                   :: uintptr(3)
+SYS_stat                    :: uintptr(4)
+SYS_fstat                   :: uintptr(5)
+SYS_lstat                   :: uintptr(6)
+SYS_poll                    :: uintptr(7)
+SYS_lseek                   :: uintptr(8)
+SYS_mmap                    :: uintptr(9)
+SYS_mprotect                :: uintptr(10)
+SYS_munmap                  :: uintptr(11)
+SYS_brk                     :: uintptr(12)
+SYS_rt_sigaction            :: uintptr(13)
+SYS_rt_sigprocmask          :: uintptr(14)
+SYS_rt_sigreturn            :: uintptr(15)
+SYS_ioctl                   :: uintptr(16)
+SYS_pread64                 :: uintptr(17)
+SYS_pwrite64                :: uintptr(18)
+SYS_readv                   :: uintptr(19)
+SYS_writev                  :: uintptr(20)
+SYS_access                  :: uintptr(21)
+SYS_pipe                    :: uintptr(22)
+SYS_select                  :: uintptr(23)
+SYS_sched_yield             :: uintptr(24)
+SYS_mremap                  :: uintptr(25)
+SYS_msync                   :: uintptr(26)
+SYS_mincore                 :: uintptr(27)
+SYS_madvise                 :: uintptr(28)
+SYS_shmget                  :: uintptr(29)
+SYS_shmat                   :: uintptr(30)
+SYS_shmctl                  :: uintptr(31)
+SYS_dup                     :: uintptr(32)
+SYS_dup2                    :: uintptr(33)
+SYS_pause                   :: uintptr(34)
+SYS_nanosleep               :: uintptr(35)
+SYS_getitimer               :: uintptr(36)
+SYS_alarm                   :: uintptr(37)
+SYS_setitimer               :: uintptr(38)
+SYS_getpid                  :: uintptr(39)
+SYS_sendfile                :: uintptr(40)
+SYS_socket                  :: uintptr(41)
+SYS_connect                 :: uintptr(42)
+SYS_accept                  :: uintptr(43)
+SYS_sendto                  :: uintptr(44)
+SYS_recvfrom                :: uintptr(45)
+SYS_sendmsg                 :: uintptr(46)
+SYS_recvmsg                 :: uintptr(47)
+SYS_shutdown                :: uintptr(48)
+SYS_bind                    :: uintptr(49)
+SYS_listen                  :: uintptr(50)
+SYS_getsockname             :: uintptr(51)
+SYS_getpeername             :: uintptr(52)
+SYS_socketpair              :: uintptr(53)
+SYS_setsockopt              :: uintptr(54)
+SYS_getsockopt              :: uintptr(55)
+SYS_clone                   :: uintptr(56)
+SYS_fork                    :: uintptr(57)
+SYS_vfork                   :: uintptr(58)
+SYS_execve                  :: uintptr(59)
+SYS_exit                    :: uintptr(60)
+SYS_wait4                   :: uintptr(61)
+SYS_kill                    :: uintptr(62)
+SYS_uname                   :: uintptr(63)
+SYS_semget                  :: uintptr(64)
+SYS_semop                   :: uintptr(65)
+SYS_semctl                  :: uintptr(66)
+SYS_shmdt                   :: uintptr(67)
+SYS_msgget                  :: uintptr(68)
+SYS_msgsnd                  :: uintptr(69)
+SYS_msgrcv                  :: uintptr(70)
+SYS_msgctl                  :: uintptr(71)
+SYS_fcntl                   :: uintptr(72)
+SYS_flock                   :: uintptr(73)
+SYS_fsync                   :: uintptr(74)
+SYS_fdatasync               :: uintptr(75)
+SYS_truncate                :: uintptr(76)
+SYS_ftruncate               :: uintptr(77)
+SYS_getdents                :: uintptr(78)
+SYS_getcwd                  :: uintptr(79)
+SYS_chdir                   :: uintptr(80)
+SYS_fchdir                  :: uintptr(81)
+SYS_rename                  :: uintptr(82)
+SYS_mkdir                   :: uintptr(83)
+SYS_rmdir                   :: uintptr(84)
+SYS_creat                   :: uintptr(85)
+SYS_link                    :: uintptr(86)
+SYS_unlink                  :: uintptr(87)
+SYS_symlink                 :: uintptr(88)
+SYS_readlink                :: uintptr(89)
+SYS_chmod                   :: uintptr(90)
+SYS_fchmod                  :: uintptr(91)
+SYS_chown                   :: uintptr(92)
+SYS_fchown                  :: uintptr(93)
+SYS_lchown                  :: uintptr(94)
+SYS_umask                   :: uintptr(95)
+SYS_gettimeofday            :: uintptr(96)
+SYS_getrlimit               :: uintptr(97)
+SYS_getrusage               :: uintptr(98)
+SYS_sysinfo                 :: uintptr(99)
+SYS_times                   :: uintptr(100)
+SYS_ptrace                  :: uintptr(101)
+SYS_getuid                  :: uintptr(102)
+SYS_syslog                  :: uintptr(103)
+SYS_getgid                  :: uintptr(104)
+SYS_setuid                  :: uintptr(105)
+SYS_setgid                  :: uintptr(106)
+SYS_geteuid                 :: uintptr(107)
+SYS_getegid                 :: uintptr(108)
+SYS_setpgid                 :: uintptr(109)
+SYS_getppid                 :: uintptr(110)
+SYS_getpgrp                 :: uintptr(111)
+SYS_setsid                  :: uintptr(112)
+SYS_setreuid                :: uintptr(113)
+SYS_setregid                :: uintptr(114)
+SYS_getgroups               :: uintptr(115)
+SYS_setgroups               :: uintptr(116)
+SYS_setresuid               :: uintptr(117)
+SYS_getresuid               :: uintptr(118)
+SYS_setresgid               :: uintptr(119)
+SYS_getresgid               :: uintptr(120)
+SYS_getpgid                 :: uintptr(121)
+SYS_setfsuid                :: uintptr(122)
+SYS_setfsgid                :: uintptr(123)
+SYS_getsid                  :: uintptr(124)
+SYS_capget                  :: uintptr(125)
+SYS_capset                  :: uintptr(126)
+SYS_rt_sigpending           :: uintptr(127)
+SYS_rt_sigtimedwait         :: uintptr(128)
+SYS_rt_sigqueueinfo         :: uintptr(129)
+SYS_rt_sigsuspend           :: uintptr(130)
+SYS_sigaltstack             :: uintptr(131)
+SYS_utime                   :: uintptr(132)
+SYS_mknod                   :: uintptr(133)
+SYS_uselib                  :: uintptr(134)
+SYS_personality             :: uintptr(135)
+SYS_ustat                   :: uintptr(136)
+SYS_statfs                  :: uintptr(137)
+SYS_fstatfs                 :: uintptr(138)
+SYS_sysfs                   :: uintptr(139)
+SYS_getpriority             :: uintptr(140)
+SYS_setpriority             :: uintptr(141)
+SYS_sched_setparam          :: uintptr(142)
+SYS_sched_getparam          :: uintptr(143)
+SYS_sched_setscheduler      :: uintptr(144)
+SYS_sched_getscheduler      :: uintptr(145)
+SYS_sched_get_priority_max  :: uintptr(146)
+SYS_sched_get_priority_min  :: uintptr(147)
+SYS_sched_rr_get_interval   :: uintptr(148)
+SYS_mlock                   :: uintptr(149)
+SYS_munlock                 :: uintptr(150)
+SYS_mlockall                :: uintptr(151)
+SYS_munlockall              :: uintptr(152)
+SYS_vhangup                 :: uintptr(153)
+SYS_modify_ldt              :: uintptr(154)
+SYS_pivot_root              :: uintptr(155)
+SYS__sysctl                 :: uintptr(156)
+SYS_prctl                   :: uintptr(157)
+SYS_arch_prctl              :: uintptr(158)
+SYS_adjtimex                :: uintptr(159)
+SYS_setrlimit               :: uintptr(160)
+SYS_chroot                  :: uintptr(161)
+SYS_sync                    :: uintptr(162)
+SYS_acct                    :: uintptr(163)
+SYS_settimeofday            :: uintptr(164)
+SYS_mount                   :: uintptr(165)
+SYS_umount2                 :: uintptr(166)
+SYS_swapon                  :: uintptr(167)
+SYS_swapoff                 :: uintptr(168)
+SYS_reboot                  :: uintptr(169)
+SYS_sethostname             :: uintptr(170)
+SYS_setdomainname           :: uintptr(171)
+SYS_iopl                    :: uintptr(172)
+SYS_ioperm                  :: uintptr(173)
+SYS_create_module           :: uintptr(174)
+SYS_init_module             :: uintptr(175)
+SYS_delete_module           :: uintptr(176)
+SYS_get_kernel_syms         :: uintptr(177)
+SYS_query_module            :: uintptr(178)
+SYS_quotactl                :: uintptr(179)
+SYS_nfsservctl              :: uintptr(180)
+SYS_getpmsg                 :: uintptr(181)
+SYS_putpmsg                 :: uintptr(182)
+SYS_afs_syscall             :: uintptr(183)
+SYS_tuxcall                 :: uintptr(184)
+SYS_security                :: uintptr(185)
+SYS_gettid                  :: uintptr(186)
+SYS_readahead               :: uintptr(187)
+SYS_setxattr                :: uintptr(188)
+SYS_lsetxattr               :: uintptr(189)
+SYS_fsetxattr               :: uintptr(190)
+SYS_getxattr                :: uintptr(191)
+SYS_lgetxattr               :: uintptr(192)
+SYS_fgetxattr               :: uintptr(193)
+SYS_listxattr               :: uintptr(194)
+SYS_llistxattr              :: uintptr(195)
+SYS_flistxattr              :: uintptr(196)
+SYS_removexattr             :: uintptr(197)
+SYS_lremovexattr            :: uintptr(198)
+SYS_fremovexattr            :: uintptr(199)
+SYS_tkill                   :: uintptr(200)
+SYS_time                    :: uintptr(201)
+SYS_futex                   :: uintptr(202)
+SYS_sched_setaffinity       :: uintptr(203)
+SYS_sched_getaffinity       :: uintptr(204)
+SYS_set_thread_area         :: uintptr(205)
+SYS_io_setup                :: uintptr(206)
+SYS_io_destroy              :: uintptr(207)
+SYS_io_getevents            :: uintptr(208)
+SYS_io_submit               :: uintptr(209)
+SYS_io_cancel               :: uintptr(210)
+SYS_get_thread_area         :: uintptr(211)
+SYS_lookup_dcookie          :: uintptr(212)
+SYS_epoll_create            :: uintptr(213)
+SYS_epoll_ctl_old           :: uintptr(214)
+SYS_epoll_wait_old          :: uintptr(215)
+SYS_remap_file_pages        :: uintptr(216)
+SYS_getdents64              :: uintptr(217)
+SYS_set_tid_address         :: uintptr(218)
+SYS_restart_syscall         :: uintptr(219)
+SYS_semtimedop              :: uintptr(220)
+SYS_fadvise64               :: uintptr(221)
+SYS_timer_create            :: uintptr(222)
+SYS_timer_settime           :: uintptr(223)
+SYS_timer_gettime           :: uintptr(224)
+SYS_timer_getoverrun        :: uintptr(225)
+SYS_timer_delete            :: uintptr(226)
+SYS_clock_settime           :: uintptr(227)
+SYS_clock_gettime           :: uintptr(228)
+SYS_clock_getres            :: uintptr(229)
+SYS_clock_nanosleep         :: uintptr(230)
+SYS_exit_group              :: uintptr(231)
+SYS_epoll_wait              :: uintptr(232)
+SYS_epoll_ctl               :: uintptr(233)
+SYS_tgkill                  :: uintptr(234)
+SYS_utimes                  :: uintptr(235)
+SYS_vserver                 :: uintptr(236)
+SYS_mbind                   :: uintptr(237)
+SYS_set_mempolicy           :: uintptr(238)
+SYS_get_mempolicy           :: uintptr(239)
+SYS_mq_open                 :: uintptr(240)
+SYS_mq_unlink               :: uintptr(241)
+SYS_mq_timedsend            :: uintptr(242)
+SYS_mq_timedreceive         :: uintptr(243)
+SYS_mq_notify               :: uintptr(244)
+SYS_mq_getsetattr           :: uintptr(245)
+SYS_kexec_load              :: uintptr(246)
+SYS_waitid                  :: uintptr(247)
+SYS_add_key                 :: uintptr(248)
+SYS_request_key             :: uintptr(249)
+SYS_keyctl                  :: uintptr(250)
+SYS_ioprio_set              :: uintptr(251)
+SYS_ioprio_get              :: uintptr(252)
+SYS_inotify_init            :: uintptr(253)
+SYS_inotify_add_watch       :: uintptr(254)
+SYS_inotify_rm_watch        :: uintptr(255)
+SYS_migrate_pages           :: uintptr(256)
+SYS_openat                  :: uintptr(257)
+SYS_mkdirat                 :: uintptr(258)
+SYS_mknodat                 :: uintptr(259)
+SYS_fchownat                :: uintptr(260)
+SYS_futimesat               :: uintptr(261)
+SYS_newfstatat              :: uintptr(262)
+SYS_unlinkat                :: uintptr(263)
+SYS_renameat                :: uintptr(264)
+SYS_linkat                  :: uintptr(265)
+SYS_symlinkat               :: uintptr(266)
+SYS_readlinkat              :: uintptr(267)
+SYS_fchmodat                :: uintptr(268)
+SYS_faccessat               :: uintptr(269)
+SYS_pselect6                :: uintptr(270)
+SYS_ppoll                   :: uintptr(271)
+SYS_unshare                 :: uintptr(272)
+SYS_set_robust_list         :: uintptr(273)
+SYS_get_robust_list         :: uintptr(274)
+SYS_splice                  :: uintptr(275)
+SYS_tee                     :: uintptr(276)
+SYS_sync_file_range         :: uintptr(277)
+SYS_vmsplice                :: uintptr(278)
+SYS_move_pages              :: uintptr(279)
+SYS_utimensat               :: uintptr(280)
+SYS_epoll_pwait             :: uintptr(281)
+SYS_signalfd                :: uintptr(282)
+SYS_timerfd_create          :: uintptr(283)
+SYS_eventfd                 :: uintptr(284)
+SYS_fallocate               :: uintptr(285)
+SYS_timerfd_settime         :: uintptr(286)
+SYS_timerfd_gettime         :: uintptr(287)
+SYS_accept4                 :: uintptr(288)
+SYS_signalfd4               :: uintptr(289)
+SYS_eventfd2                :: uintptr(290)
+SYS_epoll_create1           :: uintptr(291)
+SYS_dup3                    :: uintptr(292)
+SYS_pipe2                   :: uintptr(293)
+SYS_inotify_init1           :: uintptr(294)
+SYS_preadv                  :: uintptr(295)
+SYS_pwritev                 :: uintptr(296)
+SYS_rt_tgsigqueueinfo       :: uintptr(297)
+SYS_perf_event_open         :: uintptr(298)
+SYS_recvmmsg                :: uintptr(299)
+SYS_fanotify_init           :: uintptr(300)
+SYS_fanotify_mark           :: uintptr(301)
+SYS_prlimit64               :: uintptr(302)
+SYS_name_to_handle_at       :: uintptr(303)
+SYS_open_by_handle_at       :: uintptr(304)
+SYS_clock_adjtime           :: uintptr(305)
+SYS_syncfs                  :: uintptr(306)
+SYS_sendmmsg                :: uintptr(307)
+SYS_setns                   :: uintptr(308)
+SYS_getcpu                  :: uintptr(309)
+SYS_process_vm_readv        :: uintptr(310)
+SYS_process_vm_writev       :: uintptr(311)
+SYS_kcmp                    :: uintptr(312)
+SYS_finit_module            :: uintptr(313)
+SYS_sched_setattr           :: uintptr(314)
+SYS_sched_getattr           :: uintptr(315)
+SYS_renameat2               :: uintptr(316)
+SYS_seccomp                 :: uintptr(317)
+SYS_getrandom               :: uintptr(318)
+SYS_memfd_create            :: uintptr(319)
+SYS_kexec_file_load         :: uintptr(320)
+SYS_bpf                     :: uintptr(321)
+SYS_execveat                :: uintptr(322)
+SYS_userfaultfd             :: uintptr(323)
+SYS_membarrier              :: uintptr(324)
+SYS_mlock2                  :: uintptr(325)
+SYS_copy_file_range         :: uintptr(326)
+SYS_preadv2                 :: uintptr(327)
+SYS_pwritev2                :: uintptr(328)
+SYS_pkey_mprotect           :: uintptr(329)
+SYS_pkey_alloc              :: uintptr(330)
+SYS_pkey_free               :: uintptr(331)
+SYS_statx                   :: uintptr(332)
+SYS_io_pgetevents           :: uintptr(333)
+SYS_rseq                    :: uintptr(334)
+SYS_pidfd_send_signal       :: uintptr(424)
+SYS_io_uring_setup          :: uintptr(425)
+SYS_io_uring_enter          :: uintptr(426)
+SYS_io_uring_register       :: uintptr(427)
+SYS_open_tree               :: uintptr(428)
+SYS_move_mount              :: uintptr(429)
+SYS_fsopen                  :: uintptr(430)
+SYS_fsconfig                :: uintptr(431)
+SYS_fsmount                 :: uintptr(432)
+SYS_fspick                  :: uintptr(433)
+SYS_pidfd_open              :: uintptr(434)
+SYS_clone3                  :: uintptr(435)
+SYS_close_range             :: uintptr(436)
+SYS_openat2                 :: uintptr(437)
+SYS_pidfd_getfd             :: uintptr(438)
+SYS_faccessat2              :: uintptr(439)
+SYS_process_madvise         :: uintptr(440)
+SYS_epoll_pwait2            :: uintptr(441)
+SYS_mount_setattr           :: uintptr(442)
+SYS_quotactl_fd             :: uintptr(443)
+SYS_landlock_create_ruleset :: uintptr(444)
+SYS_landlock_add_rule       :: uintptr(445)
+SYS_landlock_restrict_self  :: uintptr(446)
+SYS_memfd_secret            :: uintptr(447)
+SYS_process_mrelease        :: uintptr(448)
+SYS_futex_waitv             :: uintptr(449)
+SYS_set_mempolicy_home_node :: uintptr(450)
+SYS_cachestat               :: uintptr(451)
+SYS_fchmodat2               :: uintptr(452)
+SYS_map_shadow_stack        :: uintptr(453)

+ 470 - 0
core/sys/linux/syscall_arm32.odin

@@ -0,0 +1,470 @@
+//+build arm32
+package linux
+
+// This file was taken and transformed from
+//   /arch/arm/tools/syscall.tbl
+// in linux headers. OABI and EABI syscalls
+// are included.
+
+// TODO(bumbread, 2023-10-13): I'm not sure whether I have used
+// the right syscall table. ARM64 stuff seems to be also compatible
+// with ARM32, I'm not sure whether ARM32 also uses the new way of
+// defining the syscall table, and this one is just for compatibility..?
+
+// This syscall is not meant to be used by userspace
+SYS_restart_syscall             :: uintptr(0)
+
+SYS_exit                        :: uintptr(1)
+SYS_fork                        :: uintptr(2)
+SYS_read                        :: uintptr(3)
+SYS_write                       :: uintptr(4)
+SYS_open                        :: uintptr(5)
+SYS_close                       :: uintptr(6)
+// 7 was sys_waitpid
+SYS_creat                       :: uintptr(8)
+SYS_link                        :: uintptr(9)
+SYS_unlink                      :: uintptr(10)
+SYS_execve                      :: uintptr(11)
+SYS_chdir                       :: uintptr(12)
+SYS_time                        :: uintptr(13)
+SYS_mknod                       :: uintptr(14)
+SYS_chmod                       :: uintptr(15)
+SYS_lchown                      :: uintptr(16)
+// 17 was sys_break
+// 18 was sys_stat
+SYS_lseek                       :: uintptr(19)
+SYS_getpid                      :: uintptr(20)
+SYS_mount                       :: uintptr(21)
+SYS_umount                      :: uintptr(22)
+SYS_setuid                      :: uintptr(23)
+SYS_getuid                      :: uintptr(24)
+SYS_stime                       :: uintptr(25)
+SYS_ptrace                      :: uintptr(26)
+SYS_alarm                       :: uintptr(27)
+// 28 was sys_fstat
+SYS_pause                       :: uintptr(29)
+SYS_utime                       :: uintptr(30)
+// 31 was sys_stty
+// 32 was sys_gtty
+SYS_access                      :: uintptr(33)
+SYS_nice                        :: uintptr(34)
+// 35 was sys_ftime
+SYS_sync                        :: uintptr(36)
+SYS_kill                        :: uintptr(37)
+SYS_rename                      :: uintptr(38)
+SYS_mkdir                       :: uintptr(39)
+SYS_rmdir                       :: uintptr(40)
+SYS_dup                         :: uintptr(41)
+SYS_pipe                        :: uintptr(42)
+SYS_times                       :: uintptr(43)
+// 44 was sys_prof
+SYS_brk                         :: uintptr(45)
+SYS_setgid                      :: uintptr(46)
+SYS_getgid                      :: uintptr(47)
+// 48 was sys_signal
+SYS_geteuid                     :: uintptr(49)
+SYS_getegid                     :: uintptr(50)
+SYS_acct                        :: uintptr(51)
+SYS_umount2                     :: uintptr(52)
+// 53 was sys_lock
+SYS_ioctl                       :: uintptr(54)
+SYS_fcntl                       :: uintptr(55)
+// 56 was sys_mpx
+SYS_setpgid                     :: uintptr(57)
+// 58 was sys_ulimit
+// 59 was sys_olduname
+SYS_umask                       :: uintptr(60)
+SYS_chroot                      :: uintptr(61)
+SYS_ustat                       :: uintptr(62)
+SYS_dup2                        :: uintptr(63)
+SYS_getppid                     :: uintptr(64)
+SYS_getpgrp                     :: uintptr(65)
+SYS_setsid                      :: uintptr(66)
+SYS_sigaction                   :: uintptr(67)
+// 68 was sys_sgetmask
+// 69 was sys_ssetmask
+SYS_setreuid                    :: uintptr(70)
+SYS_setregid                    :: uintptr(71)
+SYS_sigsuspend                  :: uintptr(72)
+SYS_sigpending                  :: uintptr(73)
+SYS_sethostname                 :: uintptr(74)
+SYS_setrlimit                   :: uintptr(75)
+// Back compat 2GB limited rlimit
+SYS_getrlimit                   :: uintptr(76)
+SYS_getrusage                   :: uintptr(77)
+SYS_gettimeofday                :: uintptr(78)
+SYS_settimeofday                :: uintptr(79)
+SYS_getgroups                   :: uintptr(80)
+SYS_setgroups                   :: uintptr(81)
+SYS_select                      :: uintptr(82)
+SYS_symlink                     :: uintptr(83)
+// 84 was sys_lstat
+SYS_readlink                    :: uintptr(85)
+SYS_uselib                      :: uintptr(86)
+SYS_swapon                      :: uintptr(87)
+SYS_reboot                      :: uintptr(88)
+SYS_readdir                     :: uintptr(89)
+SYS_mmap                        :: uintptr(90)
+SYS_munmap                      :: uintptr(91)
+SYS_truncate                    :: uintptr(92)
+SYS_ftruncate                   :: uintptr(93)
+SYS_fchmod                      :: uintptr(94)
+SYS_fchown                      :: uintptr(95)
+SYS_getpriority                 :: uintptr(96)
+SYS_setpriority                 :: uintptr(97)
+// 98 was sys_profil
+SYS_statfs                      :: uintptr(99)
+SYS_fstatfs                     :: uintptr(100)
+// 101 was sys_ioperm
+SYS_socketcall                  :: uintptr(102)
+SYS_syslog                      :: uintptr(103)
+SYS_setitimer                   :: uintptr(104)
+SYS_getitimer                   :: uintptr(105)
+SYS_stat                        :: uintptr(106)
+SYS_lstat                       :: uintptr(107)
+SYS_fstat                       :: uintptr(108)
+// 109 was sys_uname
+// 110 was sys_iopl
+SYS_vhangup                     :: uintptr(111)
+// 112 was sys_idle
+// syscall to call a syscall!
+SYS_syscall                     :: uintptr(113)
+SYS_wait4                       :: uintptr(114)
+SYS_swapoff                     :: uintptr(115)
+SYS_sysinfo                     :: uintptr(116)
+SYS_ipc                         :: uintptr(117)
+SYS_fsync                       :: uintptr(118)
+SYS_sigreturn                   :: uintptr(119)
+SYS_clone                       :: uintptr(120)
+SYS_setdomainname               :: uintptr(121)
+SYS_uname                       :: uintptr(122)
+// 123 was sys_modify_ldt
+SYS_adjtimex                    :: uintptr(124)
+SYS_mprotect                    :: uintptr(125)
+SYS_sigprocmask                 :: uintptr(126)
+// 127 was sys_create_module
+SYS_init_module                 :: uintptr(128)
+SYS_delete_module               :: uintptr(129)
+// 130 was sys_get_kernel_syms
+SYS_quotactl                    :: uintptr(131)
+SYS_getpgid                     :: uintptr(132)
+SYS_fchdir                      :: uintptr(133)
+SYS_bdflush                     :: uintptr(134)
+SYS_sysfs                       :: uintptr(135)
+SYS_personality                 :: uintptr(136)
+// 137 was sys_afs_syscall
+SYS_setfsuid                    :: uintptr(138)
+SYS_setfsgid                    :: uintptr(139)
+SYS__llseek                     :: uintptr(140)
+SYS_getdents                    :: uintptr(141)
+SYS__newselect                  :: uintptr(142)
+SYS_flock                       :: uintptr(143)
+SYS_msync                       :: uintptr(144)
+SYS_readv                       :: uintptr(145)
+SYS_writev                      :: uintptr(146)
+SYS_getsid                      :: uintptr(147)
+SYS_fdatasync                   :: uintptr(148)
+SYS__sysctl                     :: uintptr(149)
+SYS_mlock                       :: uintptr(150)
+SYS_munlock                     :: uintptr(151)
+SYS_mlockall                    :: uintptr(152)
+SYS_munlockall                  :: uintptr(153)
+SYS_sched_setparam              :: uintptr(154)
+SYS_sched_getparam              :: uintptr(155)
+SYS_sched_setscheduler          :: uintptr(156)
+SYS_sched_getscheduler          :: uintptr(157)
+SYS_sched_yield                 :: uintptr(158)
+SYS_sched_get_priority_max      :: uintptr(159)
+SYS_sched_get_priority_min      :: uintptr(160)
+SYS_sched_rr_get_interval       :: uintptr(161)
+SYS_nanosleep                   :: uintptr(162)
+SYS_mremap                      :: uintptr(163)
+SYS_setresuid                   :: uintptr(164)
+SYS_getresuid                   :: uintptr(165)
+// 166 was sys_vm86
+// 167 was sys_query_module
+SYS_poll                        :: uintptr(168)
+SYS_nfsservctl                  :: uintptr(169)
+SYS_setresgid                   :: uintptr(170)
+SYS_getresgid                   :: uintptr(171)
+SYS_prctl                       :: uintptr(172)
+SYS_rt_sigreturn                :: uintptr(173)
+SYS_rt_sigaction                :: uintptr(174)
+SYS_rt_sigprocmask              :: uintptr(175)
+SYS_rt_sigpending               :: uintptr(176)
+SYS_rt_sigtimedwait             :: uintptr(177)
+SYS_rt_sigqueueinfo             :: uintptr(178)
+SYS_rt_sigsuspend               :: uintptr(179)
+SYS_pread64                     :: uintptr(180)
+SYS_pwrite64                    :: uintptr(181)
+SYS_chown                       :: uintptr(182)
+SYS_getcwd                      :: uintptr(183)
+SYS_capget                      :: uintptr(184)
+SYS_capset                      :: uintptr(185)
+SYS_sigaltstack                 :: uintptr(186)
+SYS_sendfile                    :: uintptr(187)
+// 188 reserved
+// 189 reserved
+SYS_vfork                       :: uintptr(190)
+// SuS compliant getrlimit
+SYS_ugetrlimit                  :: uintptr(191)
+SYS_mmap2                       :: uintptr(192)
+SYS_truncate64                  :: uintptr(193)
+SYS_ftruncate64                 :: uintptr(194)
+SYS_stat64                      :: uintptr(195)
+SYS_lstat64                     :: uintptr(196)
+SYS_fstat64                     :: uintptr(197)
+SYS_lchown32                    :: uintptr(198)
+SYS_getuid32                    :: uintptr(199)
+SYS_getgid32                    :: uintptr(200)
+SYS_geteuid32                   :: uintptr(201)
+SYS_getegid32                   :: uintptr(202)
+SYS_setreuid32                  :: uintptr(203)
+SYS_setregid32                  :: uintptr(204)
+SYS_getgroups32                 :: uintptr(205)
+SYS_setgroups32                 :: uintptr(206)
+SYS_fchown32                    :: uintptr(207)
+SYS_setresuid32                 :: uintptr(208)
+SYS_getresuid32                 :: uintptr(209)
+SYS_setresgid32                 :: uintptr(210)
+SYS_getresgid32                 :: uintptr(211)
+SYS_chown32                     :: uintptr(212)
+SYS_setuid32                    :: uintptr(213)
+SYS_setgid32                    :: uintptr(214)
+SYS_setfsuid32                  :: uintptr(215)
+SYS_setfsgid32                  :: uintptr(216)
+SYS_getdents64                  :: uintptr(217)
+SYS_pivot_root                  :: uintptr(218)
+SYS_mincore                     :: uintptr(219)
+SYS_madvise                     :: uintptr(220)
+SYS_fcntl64                     :: uintptr(221)
+// 222 for tux
+// 223 is unused
+SYS_gettid                      :: uintptr(224)
+SYS_readahead                   :: uintptr(225)
+SYS_setxattr                    :: uintptr(226)
+SYS_lsetxattr                   :: uintptr(227)
+SYS_fsetxattr                   :: uintptr(228)
+SYS_getxattr                    :: uintptr(229)
+SYS_lgetxattr                   :: uintptr(230)
+SYS_fgetxattr                   :: uintptr(231)
+SYS_listxattr                   :: uintptr(232)
+SYS_llistxattr                  :: uintptr(233)
+SYS_flistxattr                  :: uintptr(234)
+SYS_removexattr                 :: uintptr(235)
+SYS_lremovexattr                :: uintptr(236)
+SYS_fremovexattr                :: uintptr(237)
+SYS_tkill                       :: uintptr(238)
+SYS_sendfile64                  :: uintptr(239)
+SYS_futex                       :: uintptr(240)
+SYS_sched_setaffinity           :: uintptr(241)
+SYS_sched_getaffinity           :: uintptr(242)
+SYS_io_setup                    :: uintptr(243)
+SYS_io_destroy                  :: uintptr(244)
+SYS_io_getevents                :: uintptr(245)
+SYS_io_submit                   :: uintptr(246)
+SYS_io_cancel                   :: uintptr(247)
+SYS_exit_group                  :: uintptr(248)
+SYS_lookup_dcookie              :: uintptr(249)
+SYS_epoll_create                :: uintptr(250)
+SYS_epoll_ctl                   :: uintptr(251)
+SYS_epoll_wait                  :: uintptr(252)
+SYS_remap_file_pages            :: uintptr(253)
+// 254 for set_thread_area
+// 255 for get_thread_area
+SYS_set_tid_address             :: uintptr(256)
+SYS_timer_create                :: uintptr(257)
+SYS_timer_settime               :: uintptr(258)
+SYS_timer_gettime               :: uintptr(259)
+SYS_timer_getoverrun            :: uintptr(260)
+SYS_timer_delete                :: uintptr(261)
+SYS_clock_settime               :: uintptr(262)
+SYS_clock_gettime               :: uintptr(263)
+SYS_clock_getres                :: uintptr(264)
+SYS_clock_nanosleep             :: uintptr(265)
+SYS_statfs64                    :: uintptr(266)
+SYS_fstatfs64                   :: uintptr(267)
+SYS_tgkill                      :: uintptr(268)
+SYS_utimes                      :: uintptr(269)
+SYS_arm_fadvise64_64            :: uintptr(270)
+SYS_pciconfig_iobase            :: uintptr(271)
+SYS_pciconfig_read              :: uintptr(272)
+SYS_pciconfig_write             :: uintptr(273)
+SYS_mq_open                     :: uintptr(274)
+SYS_mq_unlink                   :: uintptr(275)
+SYS_mq_timedsend                :: uintptr(276)
+SYS_mq_timedreceive             :: uintptr(277)
+SYS_mq_notify                   :: uintptr(278)
+SYS_mq_getsetattr               :: uintptr(279)
+SYS_waitid                      :: uintptr(280)
+SYS_socket                      :: uintptr(281)
+SYS_bind                        :: uintptr(282)
+SYS_connect                     :: uintptr(283)
+SYS_listen                      :: uintptr(284)
+SYS_accept                      :: uintptr(285)
+SYS_getsockname                 :: uintptr(286)
+SYS_getpeername                 :: uintptr(287)
+SYS_socketpair                  :: uintptr(288)
+SYS_send                        :: uintptr(289)
+SYS_sendto                      :: uintptr(290)
+SYS_recv                        :: uintptr(291)
+SYS_recvfrom                    :: uintptr(292)
+SYS_shutdown                    :: uintptr(293)
+SYS_setsockopt                  :: uintptr(294)
+SYS_getsockopt                  :: uintptr(295)
+SYS_sendmsg                     :: uintptr(296)
+SYS_recvmsg                     :: uintptr(297)
+SYS_semop                       :: uintptr(298)
+SYS_semget                      :: uintptr(299)
+SYS_semctl                      :: uintptr(300)
+SYS_msgsnd                      :: uintptr(301)
+SYS_msgrcv                      :: uintptr(302)
+SYS_msgget                      :: uintptr(303)
+SYS_msgctl                      :: uintptr(304)
+SYS_shmat                       :: uintptr(305)
+SYS_shmdt                       :: uintptr(306)
+SYS_shmget                      :: uintptr(307)
+SYS_shmctl                      :: uintptr(308)
+SYS_add_key                     :: uintptr(309)
+SYS_request_key                 :: uintptr(310)
+SYS_keyctl                      :: uintptr(311)
+SYS_semtimedop                  :: uintptr(312)
+SYS_vserver                     :: uintptr(313)
+SYS_ioprio_set                  :: uintptr(314)
+SYS_ioprio_get                  :: uintptr(315)
+SYS_inotify_init                :: uintptr(316)
+SYS_inotify_add_watch           :: uintptr(317)
+SYS_inotify_rm_watch            :: uintptr(318)
+SYS_mbind                       :: uintptr(319)
+SYS_get_mempolicy               :: uintptr(320)
+SYS_set_mempolicy               :: uintptr(321)
+SYS_openat                      :: uintptr(322)
+SYS_mkdirat                     :: uintptr(323)
+SYS_mknodat                     :: uintptr(324)
+SYS_fchownat                    :: uintptr(325)
+SYS_futimesat                   :: uintptr(326)
+SYS_fstatat64                   :: uintptr(327)
+SYS_unlinkat                    :: uintptr(328)
+SYS_renameat                    :: uintptr(329)
+SYS_linkat                      :: uintptr(330)
+SYS_symlinkat                   :: uintptr(331)
+SYS_readlinkat                  :: uintptr(332)
+SYS_fchmodat                    :: uintptr(333)
+SYS_faccessat                   :: uintptr(334)
+SYS_pselect6                    :: uintptr(335)
+SYS_ppoll                       :: uintptr(336)
+SYS_unshare                     :: uintptr(337)
+SYS_set_robust_list             :: uintptr(338)
+SYS_get_robust_list             :: uintptr(339)
+SYS_splice                      :: uintptr(340)
+SYS_arm_sync_file_range         :: uintptr(341)
+SYS_tee                         :: uintptr(342)
+SYS_vmsplice                    :: uintptr(343)
+SYS_move_pages                  :: uintptr(344)
+SYS_getcpu                      :: uintptr(345)
+SYS_epoll_pwait                 :: uintptr(346)
+SYS_kexec_load                  :: uintptr(347)
+SYS_utimensat                   :: uintptr(348)
+SYS_signalfd                    :: uintptr(349)
+SYS_timerfd_create              :: uintptr(350)
+SYS_eventfd                     :: uintptr(351)
+SYS_fallocate                   :: uintptr(352)
+SYS_timerfd_settime             :: uintptr(353)
+SYS_timerfd_gettime             :: uintptr(354)
+SYS_signalfd4                   :: uintptr(355)
+SYS_eventfd2                    :: uintptr(356)
+SYS_epoll_create1               :: uintptr(357)
+SYS_dup3                        :: uintptr(358)
+SYS_pipe2                       :: uintptr(359)
+SYS_inotify_init1               :: uintptr(360)
+SYS_preadv                      :: uintptr(361)
+SYS_pwritev                     :: uintptr(362)
+SYS_rt_tgsigqueueinfo           :: uintptr(363)
+SYS_perf_event_open             :: uintptr(364)
+SYS_recvmmsg                    :: uintptr(365)
+SYS_accept4                     :: uintptr(366)
+SYS_fanotify_init               :: uintptr(367)
+SYS_fanotify_mark               :: uintptr(368)
+SYS_prlimit64                   :: uintptr(369)
+SYS_name_to_handle_at           :: uintptr(370)
+SYS_open_by_handle_at           :: uintptr(371)
+SYS_clock_adjtime               :: uintptr(372)
+SYS_syncfs                      :: uintptr(373)
+SYS_sendmmsg                    :: uintptr(374)
+SYS_setns                       :: uintptr(375)
+SYS_process_vm_readv            :: uintptr(376)
+SYS_process_vm_writev           :: uintptr(377)
+SYS_kcmp                        :: uintptr(378)
+SYS_finit_module                :: uintptr(379)
+SYS_sched_setattr               :: uintptr(380)
+SYS_sched_getattr               :: uintptr(381)
+SYS_renameat2                   :: uintptr(382)
+SYS_seccomp                     :: uintptr(383)
+SYS_getrandom                   :: uintptr(384)
+SYS_memfd_create                :: uintptr(385)
+SYS_bpf                         :: uintptr(386)
+SYS_execveat                    :: uintptr(387)
+SYS_userfaultfd                 :: uintptr(388)
+SYS_membarrier                  :: uintptr(389)
+SYS_mlock2                      :: uintptr(390)
+SYS_copy_file_range             :: uintptr(391)
+SYS_preadv2                     :: uintptr(392)
+SYS_pwritev2                    :: uintptr(393)
+SYS_pkey_mprotect               :: uintptr(394)
+SYS_pkey_alloc                  :: uintptr(395)
+SYS_pkey_free                   :: uintptr(396)
+SYS_statx                       :: uintptr(397)
+SYS_rseq                        :: uintptr(398)
+SYS_io_pgetevents               :: uintptr(399)
+SYS_migrate_pages               :: uintptr(400)
+SYS_kexec_file_load             :: uintptr(401)
+// 402 is unused
+SYS_clock_gettime64             :: uintptr(403)
+SYS_clock_settime64             :: uintptr(404)
+SYS_clock_adjtime64             :: uintptr(405)
+SYS_clock_getres_time64         :: uintptr(406)
+SYS_clock_nanosleep_time64      :: uintptr(407)
+SYS_timer_gettime64             :: uintptr(408)
+SYS_timer_settime64             :: uintptr(409)
+SYS_timerfd_gettime64           :: uintptr(410)
+SYS_timerfd_settime64           :: uintptr(411)
+SYS_utimensat_time64            :: uintptr(412)
+SYS_pselect6_time64             :: uintptr(413)
+SYS_ppoll_time64                :: uintptr(414)
+SYS_io_pgetevents_time64        :: uintptr(416)
+SYS_recvmmsg_time64             :: uintptr(417)
+SYS_mq_timedsend_time64         :: uintptr(418)
+SYS_mq_timedreceive_time64      :: uintptr(419)
+SYS_semtimedop_time64           :: uintptr(420)
+SYS_rt_sigtimedwait_time64      :: uintptr(421)
+SYS_futex_time64                :: uintptr(422)
+SYS_sched_rr_get_interval_time64:: uintptr(423)
+SYS_pidfd_send_signal           :: uintptr(424)
+SYS_io_uring_setup              :: uintptr(425)
+SYS_io_uring_enter              :: uintptr(426)
+SYS_io_uring_register           :: uintptr(427)
+SYS_open_tree                   :: uintptr(428)
+SYS_move_mount                  :: uintptr(429)
+SYS_fsopen                      :: uintptr(430)
+SYS_fsconfig                    :: uintptr(431)
+SYS_fsmount                     :: uintptr(432)
+SYS_fspick                      :: uintptr(433)
+SYS_pidfd_open                  :: uintptr(434)
+SYS_clone3                      :: uintptr(435)
+SYS_close_range                 :: uintptr(436)
+SYS_openat2                     :: uintptr(437)
+SYS_pidfd_getfd                 :: uintptr(438)
+SYS_faccessat2                  :: uintptr(439)
+SYS_process_madvise             :: uintptr(440)
+SYS_epoll_pwait2                :: uintptr(441)
+SYS_mount_setattr               :: uintptr(442)
+SYS_quotactl_fd                 :: uintptr(443)
+SYS_landlock_create_ruleset     :: uintptr(444)
+SYS_landlock_add_rule           :: uintptr(445)
+SYS_landlock_restrict_self      :: uintptr(446)
+// 447 reserved for memfd_secret
+SYS_process_mrelease            :: uintptr(448)
+SYS_futex_waitv                 :: uintptr(449)
+SYS_set_mempolicy_home_node     :: uintptr(450)
+SYS_cachestat                   :: uintptr(451)
+SYS_fchmodat2                   :: uintptr(452)

+ 321 - 0
core/sys/linux/syscall_arm64.odin

@@ -0,0 +1,321 @@
+//+build arm64
+package linux
+
+// Syscalls for arm64 are defined using the new way, i.e. differently from
+// the other platforms. It defines a few constants representing which optional
+// syscalls it wants and includes the generic unistd.h file.
+
+SYS_io_setup                     :: uintptr(0)
+SYS_io_destroy                   :: uintptr(1)
+SYS_io_submit                    :: uintptr(2)
+SYS_io_cancel                    :: uintptr(3)
+// time32 syscall
+SYS_io_getevents                 :: uintptr(4)
+SYS_setxattr                     :: uintptr(5)
+SYS_lsetxattr                    :: uintptr(6)
+SYS_fsetxattr                    :: uintptr(7)
+SYS_getxattr                     :: uintptr(8)
+SYS_lgetxattr                    :: uintptr(9)
+SYS_fgetxattr                    :: uintptr(10)
+SYS_listxattr                    :: uintptr(11)
+SYS_llistxattr                   :: uintptr(12)
+SYS_flistxattr                   :: uintptr(13)
+SYS_removexattr                  :: uintptr(14)
+SYS_lremovexattr                 :: uintptr(15)
+SYS_fremovexattr                 :: uintptr(16)
+SYS_getcwd                       :: uintptr(17)
+SYS_lookup_dcookie               :: uintptr(18)
+SYS_eventfd2                     :: uintptr(19)
+SYS_epoll_create1                :: uintptr(20)
+SYS_epoll_ctl                    :: uintptr(21)
+SYS_epoll_pwait                  :: uintptr(22)
+SYS_dup                          :: uintptr(23)
+SYS_dup3                         :: uintptr(24)
+SYS_fcntl                        :: uintptr(25)
+SYS_inotify_init1                :: uintptr(26)
+SYS_inotify_add_watch            :: uintptr(27)
+SYS_inotify_rm_watch             :: uintptr(28)
+SYS_ioctl                        :: uintptr(29)
+SYS_ioprio_set                   :: uintptr(30)
+SYS_ioprio_get                   :: uintptr(31)
+SYS_flock                        :: uintptr(32)
+SYS_mknodat                      :: uintptr(33)
+SYS_mkdirat                      :: uintptr(34)
+SYS_unlinkat                     :: uintptr(35)
+SYS_symlinkat                    :: uintptr(36)
+SYS_linkat                       :: uintptr(37)
+SYS_renameat                     :: uintptr(38)
+SYS_umount2                      :: uintptr(39)
+SYS_mount                        :: uintptr(40)
+SYS_pivot_root                   :: uintptr(41)
+SYS_nfsservctl                   :: uintptr(42)
+SYS_statfs                       :: uintptr(43)
+SYS_fstatfs                      :: uintptr(44)
+SYS_truncate                     :: uintptr(45)
+SYS_ftruncate                    :: uintptr(46)
+SYS_fallocate                    :: uintptr(47)
+SYS_faccessat                    :: uintptr(48)
+SYS_chdir                        :: uintptr(49)
+SYS_fchdir                       :: uintptr(50)
+SYS_chroot                       :: uintptr(51)
+SYS_fchmod                       :: uintptr(52)
+SYS_fchmodat                     :: uintptr(53)
+SYS_fchownat                     :: uintptr(54)
+SYS_fchown                       :: uintptr(55)
+SYS_openat                       :: uintptr(56)
+SYS_close                        :: uintptr(57)
+SYS_vhangup                      :: uintptr(58)
+SYS_pipe2                        :: uintptr(59)
+SYS_quotactl                     :: uintptr(60)
+SYS_getdents64                   :: uintptr(61)
+SYS_lseek                        :: uintptr(62)
+SYS_read                         :: uintptr(63)
+SYS_write                        :: uintptr(64)
+SYS_readv                        :: uintptr(65)
+SYS_writev                       :: uintptr(66)
+SYS_pread64                      :: uintptr(67)
+SYS_pwrite64                     :: uintptr(68)
+SYS_preadv                       :: uintptr(69)
+SYS_pwritev                      :: uintptr(70)
+SYS_sendfile                     :: uintptr(71)
+SYS_pselect6                     :: uintptr(72)
+SYS_ppoll                        :: uintptr(73)
+SYS_signalfd4                    :: uintptr(74)
+SYS_vmsplice                     :: uintptr(75)
+SYS_splice                       :: uintptr(76)
+SYS_tee                          :: uintptr(77)
+SYS_readlinkat                   :: uintptr(78)
+SYS_fstatat                      :: uintptr(79)
+SYS_fstat                        :: uintptr(80)
+SYS_sync                         :: uintptr(81)
+SYS_fsync                        :: uintptr(82)
+SYS_fdatasync                    :: uintptr(83)
+SYS_sync_file_range              :: uintptr(84)
+SYS_timerfd_create               :: uintptr(85)
+SYS_timerfd_settime              :: uintptr(86)
+SYS_timerfd_gettime              :: uintptr(87)
+SYS_utimensat                    :: uintptr(88)
+SYS_acct                         :: uintptr(89)
+SYS_capget                       :: uintptr(90)
+SYS_capset                       :: uintptr(91)
+SYS_personality                  :: uintptr(92)
+SYS_exit                         :: uintptr(93)
+SYS_exit_group                   :: uintptr(94)
+SYS_waitid                       :: uintptr(95)
+SYS_set_tid_address              :: uintptr(96)
+SYS_unshare                      :: uintptr(97)
+SYS_futex                        :: uintptr(98)
+SYS_set_robust_list              :: uintptr(99)
+SYS_get_robust_list              :: uintptr(100)
+SYS_nanosleep                    :: uintptr(101)
+SYS_getitimer                    :: uintptr(102)
+SYS_setitimer                    :: uintptr(103)
+SYS_kexec_load                   :: uintptr(104)
+SYS_init_module                  :: uintptr(105)
+SYS_delete_module                :: uintptr(106)
+SYS_timer_create                 :: uintptr(107)
+SYS_timer_gettime                :: uintptr(108)
+SYS_timer_getoverrun             :: uintptr(109)
+SYS_timer_settime                :: uintptr(110)
+SYS_timer_delete                 :: uintptr(111)
+SYS_clock_settime                :: uintptr(112)
+SYS_clock_gettime                :: uintptr(113)
+SYS_clock_getres                 :: uintptr(114)
+SYS_clock_nanosleep              :: uintptr(115)
+SYS_syslog                       :: uintptr(116)
+SYS_ptrace                       :: uintptr(117)
+SYS_sched_setparam               :: uintptr(118)
+SYS_sched_setscheduler           :: uintptr(119)
+SYS_sched_getscheduler           :: uintptr(120)
+SYS_sched_getparam               :: uintptr(121)
+SYS_sched_setaffinity            :: uintptr(122)
+SYS_sched_getaffinity            :: uintptr(123)
+SYS_sched_yield                  :: uintptr(124)
+SYS_sched_get_priority_max       :: uintptr(125)
+SYS_sched_get_priority_min       :: uintptr(126)
+SYS_sched_rr_get_interval        :: uintptr(127)
+SYS_restart_syscall              :: uintptr(128)
+SYS_kill                         :: uintptr(129)
+SYS_tkill                        :: uintptr(130)
+SYS_tgkill                       :: uintptr(131)
+SYS_sigaltstack                  :: uintptr(132)
+SYS_rt_sigsuspend                :: uintptr(133)
+SYS_rt_sigaction                 :: uintptr(134)
+SYS_rt_sigprocmask               :: uintptr(135)
+SYS_rt_sigpending                :: uintptr(136)
+SYS_rt_sigtimedwait              :: uintptr(137)
+SYS_rt_sigqueueinfo              :: uintptr(138)
+SYS_rt_sigreturn                 :: uintptr(139)
+SYS_setpriority                  :: uintptr(140)
+SYS_getpriority                  :: uintptr(141)
+SYS_reboot                       :: uintptr(142)
+SYS_setregid                     :: uintptr(143)
+SYS_setgid                       :: uintptr(144)
+SYS_setreuid                     :: uintptr(145)
+SYS_setuid                       :: uintptr(146)
+SYS_setresuid                    :: uintptr(147)
+SYS_getresuid                    :: uintptr(148)
+SYS_setresgid                    :: uintptr(149)
+SYS_getresgid                    :: uintptr(150)
+SYS_setfsuid                     :: uintptr(151)
+SYS_setfsgid                     :: uintptr(152)
+SYS_times                        :: uintptr(153)
+SYS_setpgid                      :: uintptr(154)
+SYS_getpgid                      :: uintptr(155)
+SYS_getsid                       :: uintptr(156)
+SYS_setsid                       :: uintptr(157)
+SYS_getgroups                    :: uintptr(158)
+SYS_setgroups                    :: uintptr(159)
+SYS_uname                        :: uintptr(160)
+SYS_sethostname                  :: uintptr(161)
+SYS_setdomainname                :: uintptr(162)
+SYS_getrlimit                    :: uintptr(163)
+SYS_setrlimit                    :: uintptr(164)
+SYS_getrusage                    :: uintptr(165)
+SYS_umask                        :: uintptr(166)
+SYS_prctl                        :: uintptr(167)
+SYS_getcpu                       :: uintptr(168)
+SYS_gettimeofday                 :: uintptr(169)
+SYS_settimeofday                 :: uintptr(170)
+SYS_adjtimex                     :: uintptr(171)
+SYS_getpid                       :: uintptr(172)
+SYS_getppid                      :: uintptr(173)
+SYS_getuid                       :: uintptr(174)
+SYS_geteuid                      :: uintptr(175)
+SYS_getgid                       :: uintptr(176)
+SYS_getegid                      :: uintptr(177)
+SYS_gettid                       :: uintptr(178)
+SYS_sysinfo                      :: uintptr(179)
+SYS_mq_open                      :: uintptr(180)
+SYS_mq_unlink                    :: uintptr(181)
+SYS_mq_timedsend                 :: uintptr(182)
+SYS_mq_timedreceive              :: uintptr(183)
+SYS_mq_notify                    :: uintptr(184)
+SYS_mq_getsetattr                :: uintptr(185)
+SYS_msgget                       :: uintptr(186)
+SYS_msgctl                       :: uintptr(187)
+SYS_msgrcv                       :: uintptr(188)
+SYS_msgsnd                       :: uintptr(189)
+SYS_semget                       :: uintptr(190)
+SYS_semctl                       :: uintptr(191)
+SYS_semtimedop                   :: uintptr(192)
+SYS_semop                        :: uintptr(193)
+SYS_shmget                       :: uintptr(194)
+SYS_shmctl                       :: uintptr(195)
+SYS_shmat                        :: uintptr(196)
+SYS_shmdt                        :: uintptr(197)
+SYS_socket                       :: uintptr(198)
+SYS_socketpair                   :: uintptr(199)
+SYS_bind                         :: uintptr(200)
+SYS_listen                       :: uintptr(201)
+SYS_accept                       :: uintptr(202)
+SYS_connect                      :: uintptr(203)
+SYS_getsockname                  :: uintptr(204)
+SYS_getpeername                  :: uintptr(205)
+SYS_sendto                       :: uintptr(206)
+SYS_recvfrom                     :: uintptr(207)
+SYS_setsockopt                   :: uintptr(208)
+SYS_getsockopt                   :: uintptr(209)
+SYS_shutdown                     :: uintptr(210)
+SYS_sendmsg                      :: uintptr(211)
+SYS_recvmsg                      :: uintptr(212)
+SYS_readahead                    :: uintptr(213)
+SYS_brk                          :: uintptr(214)
+SYS_munmap                       :: uintptr(215)
+SYS_mremap                       :: uintptr(216)
+SYS_add_key                      :: uintptr(217)
+SYS_request_key                  :: uintptr(218)
+SYS_keyctl                       :: uintptr(219)
+SYS_clone                        :: uintptr(220)
+SYS_execve                       :: uintptr(221)
+SYS_mmap                         :: uintptr(222)
+SYS_fadvise64                    :: uintptr(223)
+
+/* CONFIG_MMU only */
+SYS_swapon                       :: uintptr(224)
+SYS_swapoff                      :: uintptr(225)
+SYS_mprotect                     :: uintptr(226)
+SYS_msync                        :: uintptr(227)
+SYS_mlock                        :: uintptr(228)
+SYS_munlock                      :: uintptr(229)
+SYS_mlockall                     :: uintptr(230)
+SYS_munlockall                   :: uintptr(231)
+SYS_mincore                      :: uintptr(232)
+SYS_madvise                      :: uintptr(233)
+SYS_remap_file_pages             :: uintptr(234)
+SYS_mbind                        :: uintptr(235)
+SYS_get_mempolicy                :: uintptr(236)
+SYS_set_mempolicy                :: uintptr(237)
+SYS_migrate_pages                :: uintptr(238)
+SYS_move_pages                   :: uintptr(239)
+
+SYS_rt_tgsigqueueinfo            :: uintptr(240)
+SYS_perf_event_open              :: uintptr(241)
+SYS_accept4                      :: uintptr(242)
+SYS_recvmmsg                     :: uintptr(243)
+SYS_wait4                        :: uintptr(260)
+SYS_prlimit64                    :: uintptr(261)
+SYS_fanotify_init                :: uintptr(262)
+SYS_fanotify_mark                :: uintptr(263)
+SYS_name_to_handle_at            :: uintptr(264)
+SYS_open_by_handle_at            :: uintptr(265)
+SYS_clock_adjtime                :: uintptr(266)
+SYS_syncfs                       :: uintptr(267)
+SYS_setns                        :: uintptr(268)
+SYS_sendmmsg                     :: uintptr(269)
+SYS_process_vm_readv             :: uintptr(270)
+SYS_process_vm_writev            :: uintptr(271)
+SYS_kcmp                         :: uintptr(272)
+SYS_finit_module                 :: uintptr(273)
+SYS_sched_setattr                :: uintptr(274)
+SYS_sched_getattr                :: uintptr(275)
+SYS_renameat2                    :: uintptr(276)
+SYS_seccomp                      :: uintptr(277)
+SYS_getrandom                    :: uintptr(278)
+SYS_memfd_create                 :: uintptr(279)
+SYS_bpf                          :: uintptr(280)
+SYS_execveat                     :: uintptr(281)
+SYS_userfaultfd                  :: uintptr(282)
+SYS_membarrier                   :: uintptr(283)
+SYS_mlock2                       :: uintptr(284)
+SYS_copy_file_range              :: uintptr(285)
+SYS_preadv2                      :: uintptr(286)
+SYS_pwritev2                     :: uintptr(287)
+SYS_pkey_mprotect                :: uintptr(288)
+SYS_pkey_alloc                   :: uintptr(289)
+SYS_pkey_free                    :: uintptr(290)
+SYS_statx                        :: uintptr(291)
+SYS_io_pgetevents                :: uintptr(292)
+SYS_rseq                         :: uintptr(293)
+SYS_kexec_file_load              :: uintptr(294)
+SYS_pidfd_send_signal            :: uintptr(424)
+SYS_io_uring_setup               :: uintptr(425)
+SYS_io_uring_enter               :: uintptr(426)
+SYS_io_uring_register            :: uintptr(427)
+SYS_open_tree                    :: uintptr(428)
+SYS_move_mount                   :: uintptr(429)
+SYS_fsopen                       :: uintptr(430)
+SYS_fsconfig                     :: uintptr(431)
+SYS_fsmount                      :: uintptr(432)
+SYS_fspick                       :: uintptr(433)
+SYS_pidfd_open                   :: uintptr(434)
+SYS_clone3                       :: uintptr(435)
+SYS_close_range                  :: uintptr(436)
+SYS_openat2                      :: uintptr(437)
+SYS_pidfd_getfd                  :: uintptr(438)
+SYS_faccessat2                   :: uintptr(439)
+SYS_process_madvise              :: uintptr(440)
+SYS_epoll_pwait2                 :: uintptr(441)
+SYS_mount_setattr                :: uintptr(442)
+SYS_quotactl_fd                  :: uintptr(443)
+SYS_landlock_create_ruleset      :: uintptr(444)
+SYS_landlock_add_rule            :: uintptr(445)
+SYS_landlock_restrict_self       :: uintptr(446)
+SYS_memfd_secret                 :: uintptr(447)
+SYS_process_mrelease             :: uintptr(448)
+SYS_futex_waitv                  :: uintptr(449)
+SYS_set_mempolicy_home_node      :: uintptr(450)
+SYS_cachestat                    :: uintptr(451)
+SYS_fchmodat2                    :: uintptr(452)
+
+

+ 458 - 0
core/sys/linux/syscall_i386.odin

@@ -0,0 +1,458 @@
+//+build i386
+package linux
+
+// The numbers are taken from
+//    /arch/x86/entry/syscalls/syscall_32.tbl
+// in Linux headers. Only x64 and common ABI
+// syscalls were taken, for x32 is not
+// supported by Odin
+
+// This syscall is only used by the kernel internally
+// userspace has no reason to use it.
+SYS_restart_syscall              :: uintptr(0)
+
+SYS_exit                         :: uintptr(1)
+SYS_fork                         :: uintptr(2)
+SYS_read                         :: uintptr(3)
+SYS_write                        :: uintptr(4)
+SYS_open                         :: uintptr(5)
+SYS_close                        :: uintptr(6)
+SYS_waitpid                      :: uintptr(7)
+SYS_creat                        :: uintptr(8)
+SYS_link                         :: uintptr(9)
+SYS_unlink                       :: uintptr(10)
+SYS_execve                       :: uintptr(11)
+SYS_chdir                        :: uintptr(12)
+SYS_time                         :: uintptr(13)
+SYS_mknod                        :: uintptr(14)
+SYS_chmod                        :: uintptr(15)
+SYS_lchown                       :: uintptr(16)
+SYS_break                        :: uintptr(17)
+SYS_oldstat                      :: uintptr(18)
+SYS_lseek                        :: uintptr(19)
+SYS_getpid                       :: uintptr(20)
+SYS_mount                        :: uintptr(21)
+SYS_umount                       :: uintptr(22)
+SYS_setuid                       :: uintptr(23)
+SYS_getuid                       :: uintptr(24)
+SYS_stime                        :: uintptr(25)
+SYS_ptrace                       :: uintptr(26)
+SYS_alarm                        :: uintptr(27)
+SYS_oldfstat                     :: uintptr(28)
+SYS_pause                        :: uintptr(29)
+SYS_utime                        :: uintptr(30)
+SYS_stty                         :: uintptr(31)
+SYS_gtty                         :: uintptr(32)
+SYS_access                       :: uintptr(33)
+SYS_nice                         :: uintptr(34)
+SYS_ftime                        :: uintptr(35)
+SYS_sync                         :: uintptr(36)
+SYS_kill                         :: uintptr(37)
+SYS_rename                       :: uintptr(38)
+SYS_mkdir                        :: uintptr(39)
+SYS_rmdir                        :: uintptr(40)
+SYS_dup                          :: uintptr(41)
+SYS_pipe                         :: uintptr(42)
+SYS_times                        :: uintptr(43)
+SYS_prof                         :: uintptr(44)
+SYS_brk                          :: uintptr(45)
+SYS_setgid                       :: uintptr(46)
+SYS_getgid                       :: uintptr(47)
+SYS_signal                       :: uintptr(48)
+SYS_geteuid                      :: uintptr(49)
+SYS_getegid                      :: uintptr(50)
+SYS_acct                         :: uintptr(51)
+SYS_umount2                      :: uintptr(52)
+SYS_lock                         :: uintptr(53)
+SYS_ioctl                        :: uintptr(54)
+SYS_fcntl                        :: uintptr(55)
+SYS_mpx                          :: uintptr(56)
+SYS_setpgid                      :: uintptr(57)
+SYS_ulimit                       :: uintptr(58)
+SYS_oldolduname                  :: uintptr(59)
+SYS_umask                        :: uintptr(60)
+SYS_chroot                       :: uintptr(61)
+SYS_ustat                        :: uintptr(62)
+SYS_dup2                         :: uintptr(63)
+SYS_getppid                      :: uintptr(64)
+SYS_getpgrp                      :: uintptr(65)
+SYS_setsid                       :: uintptr(66)
+SYS_sigaction                    :: uintptr(67)
+SYS_sgetmask                     :: uintptr(68)
+SYS_ssetmask                     :: uintptr(69)
+SYS_setreuid                     :: uintptr(70)
+SYS_setregid                     :: uintptr(71)
+SYS_sigsuspend                   :: uintptr(72)
+SYS_sigpending                   :: uintptr(73)
+SYS_sethostname                  :: uintptr(74)
+SYS_setrlimit                    :: uintptr(75)
+SYS_getrlimit                    :: uintptr(76)
+SYS_getrusage                    :: uintptr(77)
+SYS_gettimeofday                 :: uintptr(78)
+SYS_settimeofday                 :: uintptr(79)
+SYS_getgroups                    :: uintptr(80)
+SYS_setgroups                    :: uintptr(81)
+SYS_select                       :: uintptr(82)
+SYS_symlink                      :: uintptr(83)
+SYS_oldlstat                     :: uintptr(84)
+SYS_readlink                     :: uintptr(85)
+SYS_uselib                       :: uintptr(86)
+SYS_swapon                       :: uintptr(87)
+SYS_reboot                       :: uintptr(88)
+SYS_readdir                      :: uintptr(89)
+SYS_mmap                         :: uintptr(90)
+SYS_munmap                       :: uintptr(91)
+SYS_truncate                     :: uintptr(92)
+SYS_ftruncate                    :: uintptr(93)
+SYS_fchmod                       :: uintptr(94)
+SYS_fchown                       :: uintptr(95)
+SYS_getpriority                  :: uintptr(96)
+SYS_setpriority                  :: uintptr(97)
+SYS_profil                       :: uintptr(98)
+SYS_statfs                       :: uintptr(99)
+SYS_fstatfs                      :: uintptr(100)
+SYS_ioperm                       :: uintptr(101)
+SYS_socketcall                   :: uintptr(102)
+SYS_syslog                       :: uintptr(103)
+SYS_setitimer                    :: uintptr(104)
+SYS_getitimer                    :: uintptr(105)
+SYS_stat                         :: uintptr(106)
+SYS_lstat                        :: uintptr(107)
+SYS_fstat                        :: uintptr(108)
+SYS_olduname                     :: uintptr(109)
+SYS_iopl                         :: uintptr(110)
+SYS_vhangup                      :: uintptr(111)
+SYS_idle                         :: uintptr(112)
+SYS_vm86old                      :: uintptr(113)
+SYS_wait4                        :: uintptr(114)
+SYS_swapoff                      :: uintptr(115)
+SYS_sysinfo                      :: uintptr(116)
+SYS_ipc                          :: uintptr(117)
+SYS_fsync                        :: uintptr(118)
+SYS_sigreturn                    :: uintptr(119)
+SYS_clone                        :: uintptr(120)
+SYS_setdomainname                :: uintptr(121)
+SYS_uname                        :: uintptr(122)
+SYS_modify_ldt                   :: uintptr(123)
+SYS_adjtimex                     :: uintptr(124)
+SYS_mprotect                     :: uintptr(125)
+SYS_sigprocmask                  :: uintptr(126)
+SYS_create_module                :: uintptr(127)
+SYS_init_module                  :: uintptr(128)
+SYS_delete_module                :: uintptr(129)
+SYS_get_kernel_syms              :: uintptr(130)
+SYS_quotactl                     :: uintptr(131)
+SYS_getpgid                      :: uintptr(132)
+SYS_fchdir                       :: uintptr(133)
+SYS_bdflush                      :: uintptr(134)
+SYS_sysfs                        :: uintptr(135)
+SYS_personality                  :: uintptr(136)
+SYS_afs_syscall                  :: uintptr(137)
+SYS_setfsuid                     :: uintptr(138)
+SYS_setfsgid                     :: uintptr(139)
+SYS__llseek                      :: uintptr(140)
+SYS_getdents                     :: uintptr(141)
+SYS__newselect                   :: uintptr(142)
+SYS_flock                        :: uintptr(143)
+SYS_msync                        :: uintptr(144)
+SYS_readv                        :: uintptr(145)
+SYS_writev                       :: uintptr(146)
+SYS_getsid                       :: uintptr(147)
+SYS_fdatasync                    :: uintptr(148)
+SYS__sysctl                      :: uintptr(149)
+SYS_mlock                        :: uintptr(150)
+SYS_munlock                      :: uintptr(151)
+SYS_mlockall                     :: uintptr(152)
+SYS_munlockall                   :: uintptr(153)
+SYS_sched_setparam               :: uintptr(154)
+SYS_sched_getparam               :: uintptr(155)
+SYS_sched_setscheduler           :: uintptr(156)
+SYS_sched_getscheduler           :: uintptr(157)
+SYS_sched_yield                  :: uintptr(158)
+SYS_sched_get_priority_max       :: uintptr(159)
+SYS_sched_get_priority_min       :: uintptr(160)
+SYS_sched_rr_get_interval        :: uintptr(161)
+SYS_nanosleep                    :: uintptr(162)
+SYS_mremap                       :: uintptr(163)
+SYS_setresuid                    :: uintptr(164)
+SYS_getresuid                    :: uintptr(165)
+SYS_vm86                         :: uintptr(166)
+SYS_query_module                 :: uintptr(167)
+SYS_poll                         :: uintptr(168)
+SYS_nfsservctl                   :: uintptr(169)
+SYS_setresgid                    :: uintptr(170)
+SYS_getresgid                    :: uintptr(171)
+SYS_prctl                        :: uintptr(172)
+SYS_rt_sigreturn                 :: uintptr(173)
+SYS_rt_sigaction                 :: uintptr(174)
+SYS_rt_sigprocmask               :: uintptr(175)
+SYS_rt_sigpending                :: uintptr(176)
+SYS_rt_sigtimedwait              :: uintptr(177)
+SYS_rt_sigqueueinfo              :: uintptr(178)
+SYS_rt_sigsuspend                :: uintptr(179)
+SYS_pread64                      :: uintptr(180)
+SYS_pwrite64                     :: uintptr(181)
+SYS_chown                        :: uintptr(182)
+SYS_getcwd                       :: uintptr(183)
+SYS_capget                       :: uintptr(184)
+SYS_capset                       :: uintptr(185)
+SYS_sigaltstack                  :: uintptr(186)
+SYS_sendfile                     :: uintptr(187)
+SYS_getpmsg                      :: uintptr(188)
+SYS_putpmsg                      :: uintptr(189)
+SYS_vfork                        :: uintptr(190)
+SYS_ugetrlimit                   :: uintptr(191)
+SYS_mmap2                        :: uintptr(192)
+SYS_truncate64                   :: uintptr(193)
+SYS_ftruncate64                  :: uintptr(194)
+SYS_stat64                       :: uintptr(195)
+SYS_lstat64                      :: uintptr(196)
+SYS_fstat64                      :: uintptr(197)
+SYS_lchown32                     :: uintptr(198)
+SYS_getuid32                     :: uintptr(199)
+SYS_getgid32                     :: uintptr(200)
+SYS_geteuid32                    :: uintptr(201)
+SYS_getegid32                    :: uintptr(202)
+SYS_setreuid32                   :: uintptr(203)
+SYS_setregid32                   :: uintptr(204)
+SYS_getgroups32                  :: uintptr(205)
+SYS_setgroups32                  :: uintptr(206)
+SYS_fchown32                     :: uintptr(207)
+SYS_setresuid32                  :: uintptr(208)
+SYS_getresuid32                  :: uintptr(209)
+SYS_setresgid32                  :: uintptr(210)
+SYS_getresgid32                  :: uintptr(211)
+SYS_chown32                      :: uintptr(212)
+SYS_setuid32                     :: uintptr(213)
+SYS_setgid32                     :: uintptr(214)
+SYS_setfsuid32                   :: uintptr(215)
+SYS_setfsgid32                   :: uintptr(216)
+SYS_pivot_root                   :: uintptr(217)
+SYS_mincore                      :: uintptr(218)
+SYS_madvise                      :: uintptr(219)
+SYS_getdents64                   :: uintptr(220)
+SYS_fcntl64                      :: uintptr(221)
+// 222 is unused
+// 223 is unused
+SYS_gettid                       :: uintptr(224)
+SYS_readahead                    :: uintptr(225)
+SYS_setxattr                     :: uintptr(226)
+SYS_lsetxattr                    :: uintptr(227)
+SYS_fsetxattr                    :: uintptr(228)
+SYS_getxattr                     :: uintptr(229)
+SYS_lgetxattr                    :: uintptr(230)
+SYS_fgetxattr                    :: uintptr(231)
+SYS_listxattr                    :: uintptr(232)
+SYS_llistxattr                   :: uintptr(233)
+SYS_flistxattr                   :: uintptr(234)
+SYS_removexattr                  :: uintptr(235)
+SYS_lremovexattr                 :: uintptr(236)
+SYS_fremovexattr                 :: uintptr(237)
+SYS_tkill                        :: uintptr(238)
+SYS_sendfile64                   :: uintptr(239)
+SYS_futex                        :: uintptr(240)
+SYS_sched_setaffinity            :: uintptr(241)
+SYS_sched_getaffinity            :: uintptr(242)
+SYS_set_thread_area              :: uintptr(243)
+SYS_get_thread_area              :: uintptr(244)
+SYS_io_setup                     :: uintptr(245)
+SYS_io_destroy                   :: uintptr(246)
+SYS_io_getevents                 :: uintptr(247)
+SYS_io_submit                    :: uintptr(248)
+SYS_io_cancel                    :: uintptr(249)
+SYS_fadvise64                    :: uintptr(250)
+// 251 is available for reuse (was briefly sys_set_zone_reclaim)
+SYS_exit_group                   :: uintptr(252)
+SYS_lookup_dcookie               :: uintptr(253)
+SYS_epoll_create                 :: uintptr(254)
+SYS_epoll_ctl                    :: uintptr(255)
+SYS_epoll_wait                   :: uintptr(256)
+SYS_remap_file_pages             :: uintptr(257)
+SYS_set_tid_address              :: uintptr(258)
+SYS_timer_create                 :: uintptr(259)
+SYS_timer_settime                :: uintptr(260)
+SYS_timer_gettime                :: uintptr(261)
+SYS_timer_getoverrun             :: uintptr(262)
+SYS_timer_delete                 :: uintptr(263)
+SYS_clock_settime                :: uintptr(264)
+SYS_clock_gettime                :: uintptr(265)
+SYS_clock_getres                 :: uintptr(266)
+SYS_clock_nanosleep              :: uintptr(267)
+SYS_statfs64                     :: uintptr(268)
+SYS_fstatfs64                    :: uintptr(269)
+SYS_tgkill                       :: uintptr(270)
+SYS_utimes                       :: uintptr(271)
+SYS_fadvise64_64                 :: uintptr(272)
+SYS_vserver                      :: uintptr(273)
+SYS_mbind                        :: uintptr(274)
+SYS_get_mempolicy                :: uintptr(275)
+SYS_set_mempolicy                :: uintptr(276)
+SYS_mq_open                      :: uintptr(277)
+SYS_mq_unlink                    :: uintptr(278)
+SYS_mq_timedsend                 :: uintptr(279)
+SYS_mq_timedreceive              :: uintptr(280)
+SYS_mq_notify                    :: uintptr(281)
+SYS_mq_getsetattr                :: uintptr(282)
+SYS_kexec_load                   :: uintptr(283)
+SYS_waitid                       :: uintptr(284)
+// 285 sys_setaltroot
+SYS_add_key                      :: uintptr(286)
+SYS_request_key                  :: uintptr(287)
+SYS_keyctl                       :: uintptr(288)
+SYS_ioprio_set                   :: uintptr(289)
+SYS_ioprio_get                   :: uintptr(290)
+SYS_inotify_init                 :: uintptr(291)
+SYS_inotify_add_watch            :: uintptr(292)
+SYS_inotify_rm_watch             :: uintptr(293)
+SYS_migrate_pages                :: uintptr(294)
+SYS_openat                       :: uintptr(295)
+SYS_mkdirat                      :: uintptr(296)
+SYS_mknodat                      :: uintptr(297)
+SYS_fchownat                     :: uintptr(298)
+SYS_futimesat                    :: uintptr(299)
+SYS_fstatat64                    :: uintptr(300)
+SYS_unlinkat                     :: uintptr(301)
+SYS_renameat                     :: uintptr(302)
+SYS_linkat                       :: uintptr(303)
+SYS_symlinkat                    :: uintptr(304)
+SYS_readlinkat                   :: uintptr(305)
+SYS_fchmodat                     :: uintptr(306)
+SYS_faccessat                    :: uintptr(307)
+SYS_pselect6                     :: uintptr(308)
+SYS_ppoll                        :: uintptr(309)
+SYS_unshare                      :: uintptr(310)
+SYS_set_robust_list              :: uintptr(311)
+SYS_get_robust_list              :: uintptr(312)
+SYS_splice                       :: uintptr(313)
+SYS_sync_file_range              :: uintptr(314)
+SYS_tee                          :: uintptr(315)
+SYS_vmsplice                     :: uintptr(316)
+SYS_move_pages                   :: uintptr(317)
+SYS_getcpu                       :: uintptr(318)
+SYS_epoll_pwait                  :: uintptr(319)
+SYS_utimensat                    :: uintptr(320)
+SYS_signalfd                     :: uintptr(321)
+SYS_timerfd_create               :: uintptr(322)
+SYS_eventfd                      :: uintptr(323)
+SYS_fallocate                    :: uintptr(324)
+SYS_timerfd_settime              :: uintptr(325)
+SYS_timerfd_gettime              :: uintptr(326)
+SYS_signalfd4                    :: uintptr(327)
+SYS_eventfd2                     :: uintptr(328)
+SYS_epoll_create1                :: uintptr(329)
+SYS_dup3                         :: uintptr(330)
+SYS_pipe2                        :: uintptr(331)
+SYS_inotify_init1                :: uintptr(332)
+SYS_preadv                       :: uintptr(333)
+SYS_pwritev                      :: uintptr(334)
+SYS_rt_tgsigqueueinfo            :: uintptr(335)
+SYS_perf_event_open              :: uintptr(336)
+SYS_recvmmsg                     :: uintptr(337)
+SYS_fanotify_init                :: uintptr(338)
+SYS_fanotify_mark                :: uintptr(339)
+SYS_prlimit64                    :: uintptr(340)
+SYS_name_to_handle_at            :: uintptr(341)
+SYS_open_by_handle_at            :: uintptr(342)
+SYS_clock_adjtime                :: uintptr(343)
+SYS_syncfs                       :: uintptr(344)
+SYS_sendmmsg                     :: uintptr(345)
+SYS_setns                        :: uintptr(346)
+SYS_process_vm_readv             :: uintptr(347)
+SYS_process_vm_writev            :: uintptr(348)
+SYS_kcmp                         :: uintptr(349)
+SYS_finit_module                 :: uintptr(350)
+SYS_sched_setattr                :: uintptr(351)
+SYS_sched_getattr                :: uintptr(352)
+SYS_renameat2                    :: uintptr(353)
+SYS_seccomp                      :: uintptr(354)
+SYS_getrandom                    :: uintptr(355)
+SYS_memfd_create                 :: uintptr(356)
+SYS_bpf                          :: uintptr(357)
+SYS_execveat                     :: uintptr(358)
+SYS_socket                       :: uintptr(359)
+SYS_socketpair                   :: uintptr(360)
+SYS_bind                         :: uintptr(361)
+SYS_connect                      :: uintptr(362)
+SYS_listen                       :: uintptr(363)
+SYS_accept4                      :: uintptr(364)
+SYS_getsockopt                   :: uintptr(365)
+SYS_setsockopt                   :: uintptr(366)
+SYS_getsockname                  :: uintptr(367)
+SYS_getpeername                  :: uintptr(368)
+SYS_sendto                       :: uintptr(369)
+SYS_sendmsg                      :: uintptr(370)
+SYS_recvfrom                     :: uintptr(371)
+SYS_recvmsg                      :: uintptr(372)
+SYS_shutdown                     :: uintptr(373)
+SYS_userfaultfd                  :: uintptr(374)
+SYS_membarrier                   :: uintptr(375)
+SYS_mlock2                       :: uintptr(376)
+SYS_copy_file_range              :: uintptr(377)
+SYS_preadv2                      :: uintptr(378)
+SYS_pwritev2                     :: uintptr(379)
+SYS_pkey_mprotect                :: uintptr(380)
+SYS_pkey_alloc                   :: uintptr(381)
+SYS_pkey_free                    :: uintptr(382)
+SYS_statx                        :: uintptr(383)
+SYS_arch_prctl                   :: uintptr(384)
+SYS_io_pgetevents                :: uintptr(385)
+SYS_rseq                         :: uintptr(386)
+SYS_semget                       :: uintptr(393)
+SYS_semctl                       :: uintptr(394)
+SYS_shmget                       :: uintptr(395)
+SYS_shmctl                       :: uintptr(396)
+SYS_shmat                        :: uintptr(397)
+SYS_shmdt                        :: uintptr(398)
+SYS_msgget                       :: uintptr(399)
+SYS_msgsnd                       :: uintptr(400)
+SYS_msgrcv                       :: uintptr(401)
+SYS_msgctl                       :: uintptr(402)
+SYS_clock_gettime64              :: uintptr(403)
+SYS_clock_settime64              :: uintptr(404)
+SYS_clock_adjtime64              :: uintptr(405)
+SYS_clock_getres_time64          :: uintptr(406)
+SYS_clock_nanosleep_time64       :: uintptr(407)
+SYS_timer_gettime64              :: uintptr(408)
+SYS_timer_settime64              :: uintptr(409)
+SYS_timerfd_gettime64            :: uintptr(410)
+SYS_timerfd_settime64            :: uintptr(411)
+SYS_utimensat_time64             :: uintptr(412)
+SYS_pselect6_time64              :: uintptr(413)
+SYS_ppoll_time64                 :: uintptr(414)
+SYS_io_pgetevents_time64         :: uintptr(416)
+SYS_recvmmsg_time64              :: uintptr(417)
+SYS_mq_timedsend_time64          :: uintptr(418)
+SYS_mq_timedreceive_time64       :: uintptr(419)
+SYS_semtimedop_time64            :: uintptr(420)
+SYS_rt_sigtimedwait_time64       :: uintptr(421)
+SYS_futex_time64                 :: uintptr(422)
+SYS_sched_rr_get_interval_time64 :: uintptr(423)
+SYS_pidfd_send_signal            :: uintptr(424)
+SYS_io_uring_setup               :: uintptr(425)
+SYS_io_uring_enter               :: uintptr(426)
+SYS_io_uring_register            :: uintptr(427)
+SYS_open_tree                    :: uintptr(428)
+SYS_move_mount                   :: uintptr(429)
+SYS_fsopen                       :: uintptr(430)
+SYS_fsconfig                     :: uintptr(431)
+SYS_fsmount                      :: uintptr(432)
+SYS_fspick                       :: uintptr(433)
+SYS_pidfd_open                   :: uintptr(434)
+SYS_clone3                       :: uintptr(435)
+SYS_close_range                  :: uintptr(436)
+SYS_openat2                      :: uintptr(437)
+SYS_pidfd_getfd                  :: uintptr(438)
+SYS_faccessat2                   :: uintptr(439)
+SYS_process_madvise              :: uintptr(440)
+SYS_epoll_pwait2                 :: uintptr(441)
+SYS_mount_setattr                :: uintptr(442)
+SYS_quotactl_fd                  :: uintptr(443)
+SYS_landlock_create_ruleset      :: uintptr(444)
+SYS_landlock_add_rule            :: uintptr(445)
+SYS_landlock_restrict_self       :: uintptr(446)
+SYS_memfd_secret                 :: uintptr(447)
+SYS_process_mrelease             :: uintptr(448)
+SYS_futex_waitv                  :: uintptr(449)
+SYS_set_mempolicy_home_node      :: uintptr(450)
+SYS_cachestat                    :: uintptr(451)
+SYS_fchmodat2                    :: uintptr(452)

+ 566 - 0
core/sys/linux/types.odin

@@ -0,0 +1,566 @@
+//+build linux
+package linux
+
+/// Represents storage device handle
+Dev :: distinct int
+
+/// Represents 32-bit user id
+Uid :: distinct u32
+
+/// Represents 32-bit group id
+Gid :: distinct u32
+
+/// Process id's
+Pid :: distinct int
+
+/// Represents pid, pifd, pgid values in general
+Id :: distinct uint
+
+/// Represents a file descriptor
+Fd  :: distinct i32
+
+/// Represents a PID file descriptor
+Pid_FD :: distinct i32
+
+/// Represents 64-bit inode number for files
+/// Used pretty much only in struct Stat64 for 32-bit platforms
+Inode :: distinct u64
+
+/// Represents time with nanosecond precision
+Time_Spec :: struct {
+    time_sec:  uint,
+    time_nsec: uint,
+}
+
+/// Represents time with millisecond precision
+Time_Val :: struct {
+    seconds:      int,
+    microseconds: int,
+}
+
+/// open.2 flags
+Open_Flags :: bit_set[Open_Flags_Bits; u32]
+
+/// Flags for the file descriptor to be passed in some syscalls
+FD_Flags :: bit_set[FD_Flags_Bits; i32]
+
+/// Represents file's permission and status bits
+/// Example:
+///   When you're passing a value of this type the recommended usage is
+///     sys.Mode{.S_IXOTH, .S_IROTH} | sys.S_IRWXU | sys.S_IRWXG
+///   This would generate a mode that has full permissions for the
+///   file's owner and group, and only "read" and "execute" bits
+///   for others.
+Mode :: bit_set[Mode_Bits; u32]
+
+when ODIN_ARCH == .amd64 {
+    // x86-64 has mode and nlink swapped for some reason
+    _Arch_Stat :: struct {
+        dev:       Dev,
+        ino:       Inode,
+        nlink:     uint,
+        mode:      Mode,
+        uid:       Uid,
+        gid:       Gid,
+        _:         u32,
+        rdev:      Dev,
+        size:      uint,
+        blksize:   uint,
+        blocks:    uint,
+        atime:     Time_Spec,
+        mtime:     Time_Spec,
+        ctime:     Time_Spec,
+        _:         [3]uint,
+    }
+} else when ODIN_ARCH == .arm64 {
+    _Arch_Stat :: struct {
+        dev:        Dev,
+        ino:        Inode,
+        mode:       Mode,
+        nlink:      u32,
+        uid:        Uid,
+        gid:        Gid,
+        rdev:       Dev,
+        _:          u64,
+        size:       int,
+        blksize:    i32,
+        _:          i32,
+        blocks:     int,
+        atime:      Time_Spec,
+        mtime:      Time_Spec,
+        ctime:      Time_Spec,
+        _:          [3]uint,
+    }
+} else {
+    _Arch_Stat :: struct {
+        dev:        Dev,
+        _:          [4]u8,
+        _ino:       uint, // Old 32-bit inode number, don't use
+        mode:       Mode,
+        nlink:      u32,
+        uid:        Uid,
+        gid:        Gid,
+        rdev:       Dev,
+        size:       i64,
+        blksize:    uint,
+        blocks:     u64,
+        atim:       Time_Spec,
+        mtim:       Time_Spec,
+        ctim:       Time_Spec,
+        ino:        Inode,
+    }
+}
+
+/// Represents the file state.
+/// Mirrors struct stat in glibc/linux kernel.
+/// If you're on 32-bit platform, consider using Stat64 instead
+Stat :: struct {
+    using _impl_stat: _Arch_Stat,
+}
+
+/// Timestamp type used for Statx struct
+Statx_Timestamp :: struct {
+    sec:  i64,
+    nsec: u32,
+    _:       i32,
+}
+
+/// Query params/results for `statx()`
+Statx_Mask :: bit_set[Statx_Mask_Bits; u32]
+
+/// File attributes, returned by statx. This bitset is also
+/// used to specify which attributes are present, not just
+/// their value.
+Statx_Attr :: bit_set[Statx_Attr_Bits; u64]
+
+/// The extended Stat struct
+Statx :: struct {
+    mask:                Statx_Mask,
+    blksize:             u32,
+    attributes:          Statx_Attr,
+    nlink:               u32,
+    uid:                 Uid,
+    gid:                 Gid,
+    // Note(flysand): mode is 16-bit on linux + there's
+    // 16-bit padding following it. Since our mode is 32-bits,
+    // we're using the padding. This should be fine because
+    // the placement of that padding suggests it was going to
+    // be used for the Mode bits anyway.
+    mode:                Mode,
+    ino:                 Inode,
+    size:                u64,
+    blocks:              u64,
+    attributes_mask:     Statx_Attr,
+    atime:               Statx_Timestamp,
+    btime:               Statx_Timestamp,
+    ctime:               Statx_Timestamp,
+    mtime:               Statx_Timestamp,
+    rdev_major:          u32,
+    rdev_minor:          u32,
+    dev_major:           u32,
+    dev_minor:           u32,
+    mnt_id:              u64,
+    dio_mem_align:       u32,
+    dio_offset_align:    u32,
+    _:                   [12]u64,
+}
+
+/// Mount flags for filesystem
+FS_Flags :: bit_set[FS_Flags_Bits; u32]
+
+when size_of(int) == 8 {
+    _Arch_Stat_FS :: struct {
+        // Note(flysand): The FS_Magic bits are never above
+        // 32-bits, so it should be fine for now...
+        type:     FS_Magic,
+        _:        u32,
+        bsize:    i64,
+        blocks:   i64,
+        bfree:    i64,
+        bavail:   i64,
+        files:    i64,
+        ffree:    i64,
+        fsid :    [2]i32,
+        namelen:  i64,
+        frsize:   i64,
+        // Note(flysand): Same story as type
+        flags:    FS_Flags,
+        _:        u32,
+        spare:    [4]i64,
+    }
+} else {
+    _Arch_Stat_FS :: struct {
+        type:     FS_Magic,
+        bsize:    u32,
+        blocks:   u64,
+        bfree:    u64,
+        bavail:   u64,
+        files:    u64,
+        ffree:    u64,
+        fsid:     [2]i32,
+        namelen:  u32,
+        frsize:   u32,
+        flags:    FS_Flags,
+        spare:    [4]u32,
+    }
+}
+
+Stat_FS :: struct {
+    using _impl_stat_fs: _Arch_Stat_FS,
+}
+
+/// Flags for close_range.2
+Close_Range_Flags :: bit_set[Close_Range_Flags_Bits; u32]
+
+/// Flags for rename.2
+Rename_Flags :: bit_set[Rename_Flags_Bits; u32]
+
+/// Directory entry
+/// Recommended to use this with dirent_iterator()
+/// and dirent_name()
+Dirent :: struct {
+    ino:    Inode,
+    off:    i64,
+    reclen: u16,
+    type:   Dirent_Type,
+    name:   [0]u8, // See dirent_name
+}
+
+/// Lock record for fcntl.2
+FLock :: struct {
+    type:   FLock_Type,
+    whence: Seek_Whence,
+    start:  i64,
+    len:    i64,
+    pid:    Pid,
+}
+
+/// Flags for fcntl_notify
+FD_Notifications :: bit_set[FD_Notifications_Bits; i32]
+
+/// Seals for fcntl_add_seals
+Seal :: bit_set[Seal_Bits; i32]
+
+/// Represents owner that receives events on file updates
+F_Owner :: struct {
+    type: F_Owner_Type,
+    pid:  Pid,
+}
+
+/// Events for ppoll
+Fd_Poll_Events :: bit_set[Fd_Poll_Events_Bits; u16]
+
+/// Struct for ppoll
+Poll_Fd :: struct {
+    fd:      Fd,
+    events:  Fd_Poll_Events,
+    revents: Fd_Poll_Events,
+}
+
+/// Specifies protection for memory pages
+Mem_Protection :: bit_set[Mem_Protection_Bits; i32]
+
+/// Flags for mmap
+Map_Flags :: bit_set[Map_Flags_Bits; i32]
+
+/// Flags for mlock.2
+MLock_Flags :: bit_set[MLock_Flags_Bits; u32]
+
+/// Flags for msync.2
+MSync_Flags :: bit_set[MSync_Flags_Bits; i32]
+
+/// Access rights for pkey_alloc.2
+PKey_Access_Rights :: bit_set[PKey_Access_Bits; u32]
+
+/// Flags for mremap.2
+MRemap_Flags :: bit_set[MRemap_Flags_Bits; i32]
+
+/// Flags for getrandom syscall
+Get_Random_Flags :: bit_set[Get_Random_Flags_Bits; i32]
+
+/// Flags for perf_event_open syscall
+Perf_Flags :: bit_set[Perf_Flags_Bits; uint]
+
+Perf_Event_Flags :: distinct bit_set[Perf_Event_Flags_Bits; u64]
+
+Perf_Cap_Flags :: distinct bit_set[Perf_Cap_Flags_Bits; u64]
+
+Perf_Event_Sample_Type :: bit_set[Perf_Event_Sample_Type_Bits; u64]
+
+/// Specifies which branches to include in branch record
+Branch_Sample_Type :: bit_set[Branch_Sample_Type_Bits; u64]
+
+/// The struct for perf_event_open
+Perf_Event_Attr :: struct #packed {
+    type:               Perf_Event_Type,
+    size:               u32,
+    config: struct #raw_union {
+        hw: Perf_Hardware_Id,
+        sw: Perf_Software_Id,
+        cache: u64,
+        other: u64,
+    },
+    sample: struct #raw_union {
+        period:    u64,
+        frequency: u64,
+    },
+    sample_type:        Perf_Event_Sample_Type,
+    read_format:        Perf_Read_Format,
+    flags:              Perf_Event_Flags,
+    wakeup: struct #raw_union {
+        events:    u32,
+        watermark: u32,
+    },
+    breakpoint_type:    Hardware_Breakpoint_Type,
+    using _: struct #raw_union {
+        breakpoint_addr: u64,
+        kprobe_func:     u64,
+        uprobe_path:     u64,
+        config1:         u64,
+    },
+    using _: struct #raw_union {
+        breakpoint_len: u64,
+        kprobe_addr:    u64,
+        uprobe_offset:  u64,
+        config2:        u64,
+    },
+    branch_sample_type: Branch_Sample_Type,
+    sample_regs_user:   u64,
+    sample_stack_user:  u32,
+    clock_id:           i32, // TODO(flysand): clock_id
+    sample_regs_intr:   u64,
+    aux_watermark:      u32,
+    sample_max_stack:   u16,
+    _:                  u16,
+}
+
+/// The ring buffer structure when mmaping Perf_Event_Attr
+Perf_Event_Mmap_Page :: struct #packed {
+    version:        u32,
+    compat_version: u32,
+    lock:           u32,
+    index:          u32,
+    offset:         i64,
+    time_enabled:   u64,
+    time_running:   u64,
+    cap: struct #raw_union {
+        capabilities: u64,
+        flags: Perf_Cap_Flags,
+    },
+    pmc_width:      u16,
+    time_shift:     u16,
+    time_mult:      u32,
+    time_offset:    u64,
+    time_zero:      u64,
+    size:           u32,
+    reserved1:      u32,
+    time_cycles:    u64,
+    time_mask:      u64,
+    reserved2:      [116*8]u8,
+    data_head:      u64,
+    data_tail:      u64,
+    data_offset:    u64,
+    data_size:      u64,
+    aux_head:       u64,
+    aux_tail:       u64,
+    aux_offset:     u64,
+    aux_size:       u64,
+}
+
+// TODO(flysand): Its taking too much effort to bind the other data structures related to perf_event_open
+
+/// Options for wait4() and waitpid()
+Wait_Options :: bit_set[Wait_Option; i32]
+
+/// Flags for pidfd_open.2
+Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32]
+
+// Note(flysand): these could, in principle be implemented with bitfields,
+// however there are ABI differences between odin's bitfields and linux sigsets.
+// Mainly:
+//  1. Odin's bitfields start from 0, whereas signals start from 1
+//  2. It's unclear how bitfields act in terms of ABI (are they an array of ints or an array of longs?).
+//     it makes a difference because ARM is big endian.
+@private _SIGSET_NWORDS :: (1024 / (8 * size_of(uint)))
+Sig_Set :: [_SIGSET_NWORDS]uint
+
+@private SI_MAX_SIZE       :: 128
+@private SI_ARCH_PREAMBLE  :: 3 * size_of(i32)
+@private SI_PAD_SIZE       :: (SI_MAX_SIZE - SI_ARCH_PREAMBLE) / size_of(i32)
+@private SI_TIMER_PAD_SIZE :: size_of(Uid) - size_of(i32)
+
+Sig_Handler_Fn :: #type proc "c" (sig: Signal)
+Sig_Restore_Fn :: #type proc "c" ()
+
+Sig_Info :: struct #packed {
+    signo: Signal,
+    errno: Errno,
+    code: i32,
+    _pad0: i32,
+    using _union: struct #raw_union {
+        _pad1: [SI_PAD_SIZE]u8,
+        using _kill: struct {
+            pid: Pid, /* sender's pid */
+            uid: Uid, /* sender's uid */
+        },
+        using _timer: struct {
+            timerid: i32,       /* timer id */
+            overrun: i32,   /* overrun count */
+        },
+        /* POSIX.1b signals */
+        using _rt: struct {
+            _pid0: Pid, /* sender's pid */
+            _uid0: Uid, /* sender's uid */
+        },
+        /* SIGCHLD */
+        using _sigchld: struct {
+            _pid1: Pid,      /* which child */
+            _uid1: Uid,      /* sender's uid */
+            status: i32, /* exit code */
+            utime: uint,
+            stime: uint, //clock_t
+        },
+        /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+        using _sigfault: struct {
+            addr: rawptr, /* faulting insn/memory ref. */
+            addr_lsb: i16, /* LSB of the reported address */
+        },
+        /* SIGPOLL */
+        using _sigpoll: struct {
+            band: int, /* POLL_IN, POLL_OUT, POLL_MSG */
+            fd: Fd,
+        },
+        /* SIGSYS */
+        using _sigsys: struct {
+            call_addr: rawptr, /* calling user insn */
+            syscall: i32,    /* triggering system call number */
+            arch: u32,      /* AUDIT_ARCH_* of syscall */
+        },
+    },
+}
+
+Sig_Stack_Flags :: bit_set[Sig_Stack_Flag; i32]
+
+Sig_Stack :: struct {
+    sp: rawptr,
+    flags: Sig_Stack_Flags,
+    size: uintptr,
+}
+
+Sig_Action :: struct($T: typeid) {
+    using _u: struct #raw_union {
+        handler: Sig_Handler_Fn,
+        sigaction: #type proc "c" (sig: Signal, si: ^Sig_Info, ctx: ^T),
+    },
+    flags: uint,
+    restorer: Sig_Restore_Fn,
+    mask: Sig_Set,
+}
+
+
+/// Flags for the socket file descriptor
+/// Note, on linux these are technically passed by OR'ing together
+/// with Socket_Type, our wrapper does this under the hood.
+Socket_FD_Flags :: bit_set[Socket_FD_Flags_Bits; int]
+
+/// Address family for the socket
+/// Typically there's one address family for every protocol family
+Address_Family :: distinct Protocol_Family
+
+/// Flags for the socket for send/recv calls
+Socket_Msg :: bit_set[Socket_Msg_Bits; i32]
+
+/// Struct representing IPv4 socket address
+Sock_Addr_In :: struct #packed {
+    sin_family: Address_Family,
+    sin_port:   u16be,
+    sin_addr:   [4]u8,
+}
+
+/// Struct representing IPv6 socket address
+Sock_Addr_In6 :: struct #packed {
+    sin6_family:   Address_Family,
+    sin6_port:     u16be,
+    sin6_flowinfo: u32,
+    sin6_addr:     [16]u8,
+    sin6_scope_id: u32,
+}
+
+/// Struct representing an arbitrary socket address
+Sock_Addr_Any :: struct #raw_union {
+    using _: struct {
+        family: Address_Family,
+        port:   u16be,
+    },
+    using ipv4: Sock_Addr_In,
+    using ipv6: Sock_Addr_In6,
+}
+
+/// Just an alias to make futex-values more visible
+Futex :: u32
+
+/// Flags for the futex (they are kept separately)
+Futex_Flags :: bit_set[Futex_Flags_Bits; u32]
+
+/// Times
+Tms :: struct {
+    tms_utime:  int,
+    tms_stime:  int,
+    tms_cutime: int,
+    tms_cstime: int,
+}
+
+/// "Unix time-sharing system name", allegedly
+/// Basically system info
+UTS_Name :: struct {
+    sysname:    [65]u8 `fmt:"s,0"`,
+    nodename:   [65]u8 `fmt:"s,0"`,
+    release:    [65]u8 `fmt:"s,0"`,
+    version:    [65]u8 `fmt:"s,0"`,
+    machine:    [65]u8 `fmt:"s,0"`,
+    domainname: [65]u8 `fmt:"s,0"`,
+}
+
+/// Return buffer for the sysinfo syscall
+Sys_Info :: struct {
+    uptime:    int,
+    loads:     [3]int,
+    totalram:  uint,
+    freeram:   uint,
+    sharedram: uint,
+    bufferram: uint,
+    totalswap: uint,
+    freeswap:  uint,
+    procs:     u16,
+    totalhigh: uint,
+    freehigh:  uint,
+    mem_unit:  i32,
+    _padding:  [20 - (2 * size_of(int)) - size_of(i32)]u8,
+}
+
+/// Resource limit
+RLimit :: struct {
+    cur: uint,
+    max: uint,
+}
+
+/// Structure representing how much of each resource
+/// got used.
+RUsage :: struct {
+    utime:         Time_Val,
+    stime:         Time_Val,
+    maxrss_word:   int,
+    ixrss_word:    int,
+    idrss_word:    int,
+    isrss_word:    int,
+    minflt_word:   int,
+    majflt_word:   int,
+    nswap_word:    int,
+    inblock_word:  int,
+    oublock_word:  int,
+    msgsnd_word:   int,
+    msgrcv_word:   int,
+    nsignals_word: int,
+    nvcsw_word:    int,
+    nivcsw_word:   int,
+}

+ 121 - 0
core/sys/linux/wrappers.odin

@@ -0,0 +1,121 @@
+//+build linux
+package linux
+
+/// Low 8 bits of the exit code
+/// Only retrieve the exit code if WIFEXITED(s) = true
+WEXITSTATUS :: #force_inline proc "contextless" (s: u32) -> u32 {
+    return (s & 0xff00) >> 8
+}
+
+/// Termination signal
+/// Only retrieve the code if WIFSIGNALED(s) = true
+WTERMSIG :: #force_inline proc "contextless" (s: u32) -> u32 {
+    return s & 0x7f
+}
+
+/// The signal that stopped the child
+/// Only retrieve if WIFSTOPPED(s) = true
+WSTOPSIG :: #force_inline proc "contextless" (s: u32) -> u32 {
+    return WEXITSTATUS(s)
+}
+
+/// Check if the process terminated normally (via exit.2)
+WIFEXITED :: #force_inline proc "contextless" (s: u32) -> bool {
+    return WTERMSIG(s) == 0
+}
+
+/// Check if the process signaled
+WIFSIGNALED :: #force_inline proc "contextless" (s: u32) -> bool {
+    return cast(i8)(((s) & 0x7f) + 1) >> 1 > 0
+}
+
+/// Check if the process has stopped
+WIFSTOPPED :: #force_inline proc "contextless" (s: u32) -> bool {
+    return (s & 0xff) == 0x7f
+}
+
+/// Check if the process is continued by the tracee
+WIFCONTINUED :: #force_inline proc "contextless" (s: u32) -> bool {
+    return s == 0xffff
+}
+
+/// Check if the process dumped core
+WCOREDUMP :: #force_inline proc "contextless" (s: u32) -> bool {
+    return s & 0x80 == 0x80
+}
+
+@private _sigmask :: proc "contextless" (sig: Signal) -> (uint) {
+    return 1 << ((cast(uint)(sig) - 1) % (8*size_of(uint)))
+}
+@private _sigword :: proc "contextless" (sig: Signal) -> (uint) {
+  return (cast(uint)sig - 1) / (8*size_of(uint))
+}
+
+// TODO: sigaddset etc
+
+
+/// Iterate the results of getdents
+/// Only iterates as much data as loaded in the buffer
+/// In case you need to iterate *all* files in a directory
+/// consider using dirent_get_iterate
+///
+/// Example of using dirent_iterate_buf
+///   // Get dirents into a buffer
+///   buf: [128]u8
+///   sys.getdents(dirfd, buf[:])
+///   // Print the names of the files
+///   for dir in sys.dirent_iterate_buf(buf[:], &offs) {
+///       name := sys.dirent_name(dir)
+///       fmt.println(name)
+///   }
+/// This function doesn't automatically make a request
+/// for the buffer to be refilled
+dirent_iterate_buf :: proc "contextless" (buf: []u8, offs: ^int) -> (d: ^Dirent, cont: bool) {
+    // Stopped iterating when there's no space left
+    if offs^ >= len(buf) {
+        return nil, false
+    }
+    // Retrieve dirent form the current offset
+    dirent := cast(^Dirent) &buf[offs^]
+    // Add the stride of dirent struct to the current offset
+    offs^ += cast(int) dirent.reclen
+    return dirent, true
+}
+
+/// Obtain the name of dirent as a string
+/// The lifetime of the string is bound to the lifetime of the provided dirent structure
+dirent_name :: proc "contextless" (dirent: ^Dirent) -> string #no_bounds_check {
+    str := transmute([^]u8) &dirent.name
+    // Note(flysand): The string size calculated above applies only to the ideal case
+    // we subtract 1 byte from the string size, because a null terminator is guaranteed
+    // to be present. But! That said, the dirents are aligned to 8 bytes and the padding
+    // between the null terminator and the start of the next struct may be not initialized
+    // which means we also have to scan these garbage bytes.
+    str_size := (cast(int) dirent.reclen) - 1 - cast(int) offset_of(Dirent, name)
+    // This skips *only* over the garbage, since if we're not garbage we're at nul terminator,
+    // which skips this loop
+    for str[str_size] != 0 {
+        str_size -= 1
+    }
+    for str[str_size-1] == 0 {
+        str_size -= 1
+    }
+    // Oh yeah btw i could also just `repne scasb` this thing, but honestly I started doing
+    // it the painful way, might as well finish doing it that way
+    return string(str[:str_size])
+}
+
+/// Constructor for the `futex_op` argument of a FUTEX_WAKE_OP call
+futex_op :: proc "contextless" (arg_op: Futex_Arg_Op, cmp_op: Futex_Cmp_Op, op_arg: u32, cmp_arg: u32) -> u32 {
+    arg_op := cast(u32) arg_op
+    cmp_op := cast(u32) cmp_op
+    return (arg_op << 28) | (cmp_op << 24) | ((op_arg & 0xfff) << 12) | (cmp_arg & 0xfff)
+}
+
+/// Helper function for constructing the config for caches
+perf_cache_config :: #force_inline proc "contextless" (id: Perf_Hardware_Cache_Id,
+    op: Perf_Hardware_Cache_Op_Id,
+    res: Perf_Hardware_Cache_Result_Id) -> u64
+{
+    return u64(id) | (u64(op) << 8) | (u64(res) << 16)
+}

+ 14 - 16
core/time/tsc_linux.odin

@@ -2,34 +2,32 @@
 //+build linux
 package time
 
-import "core:intrinsics"
-import "core:sys/unix"
+import linux "core:sys/linux"
 
 _get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
-	perf_attr := unix.Perf_Event_Attr{}
-	perf_attr.type = u32(unix.Perf_Type_Id.Hardware)
-	perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions)
+	// Get the file descriptor for the perf mapping
+	perf_attr := linux.Perf_Event_Attr{}
 	perf_attr.size = size_of(perf_attr)
+	perf_attr.type = .HARDWARE
+	perf_attr.config.hw = .INSTRUCTIONS
 	perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV}
-	fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0)
-	if fd == -1 {
+	fd, perf_errno := linux.perf_event_open(&perf_attr, linux.Pid(0), -1, linux.Fd(-1), {})
+	if perf_errno != nil {
 		return 0, false
 	}
-	defer unix.sys_close(fd)
-
+	defer linux.close(fd)
+	// Map it into the memory
 	page_size : uint = 4096
-	ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0)
-	if ret < 0 && ret > -4096 {
+	addr, mmap_errno := linux.mmap(0, page_size, {.READ}, {.SHARED}, fd)
+	if mmap_errno != nil {
 		return 0, false
 	}
-	addr := rawptr(uintptr(ret))
-	defer unix.sys_munmap(addr, page_size)
-
-	event_page := (^unix.Perf_Event_mmap_Page)(addr)
+	defer linux.munmap(addr, page_size)
+	// Get the frequency from the mapped page
+	event_page := cast(^linux.Perf_Event_Mmap_Page) addr
 	if .User_Time not_in event_page.cap.flags {
 		return 0, false
 	}
-
 	frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult))
 	return frequency, true
 }

+ 6 - 0
examples/all/all_linux.odin

@@ -0,0 +1,6 @@
+//+build linux
+package all
+
+import linux "core:sys/linux"
+
+_ :: linux

+ 11 - 8
examples/all/all_vendor.odin

@@ -39,10 +39,13 @@ import TTF        "vendor:sdl2/ttf"
 
 import vk         "vendor:vulkan"
 
-import NS         "vendor:darwin/Foundation"
-import MTL        "vendor:darwin/Metal"
-import MTK        "vendor:darwin/MetalKit"
-import CA         "vendor:darwin/QuartzCore"
+// NOTE(flysand): Since conditional imports are disabled for now I'll have to just disable these
+// when ODIN_OS == "darwin" {
+//     import NS         "vendor:darwin/Foundation"
+//     import MTL        "vendor:darwin/Metal"
+//     import MTK        "vendor:darwin/MetalKit"
+//     import CA         "vendor:darwin/QuartzCore"
+// }
 
 // NOTE(bill): only one can be checked at a time
 import lua_5_4    "vendor:lua/5.4"
@@ -91,10 +94,10 @@ _ :: TTF
 
 _ :: vk
 
-_ :: NS
-_ :: MTL
-_ :: MTK
-_ :: CA
+// _ :: NS
+// _ :: MTL
+// _ :: MTK
+// _ :: CA
 
 _ :: lua_5_4
 

+ 0 - 30
examples/test-freestanding/main.odin

@@ -1,30 +0,0 @@
-package main
-
-import "core:intrinsics"
-
-SUS_exit :: uintptr(60)
-SUS_write ::uintptr(1)
-STDOUT_FILENO :: int(1)
-
-sus_write :: proc "contextless" (fd: int, buf: cstring, size: uint) -> int {
-    return int(intrinsics.syscall(
-        SUS_write,
-        cast(uintptr) fd,
-        cast(uintptr) cast(rawptr) buf,
-        cast(uintptr) size
-    ))
-}
-
-@(link_name = "sussy_baka")
-sus_exit :: proc "contextless" (code: $T)->! {
-    intrinsics.syscall(SUS_exit, uintptr(code))
-    unreachable()
-}
-
-sus :: proc {sus_write, sus_exit}
-
-@(link_name="_start", export) _start :: proc "c" ()->! {
-    str :: cstring("Hello, world!\n")
-    sus_write(STDOUT_FILENO, str, uint(14));
-    sus_exit(0)
-}