aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/crypto/rand_linux.odin43
-rw-r--r--core/math/rand/system_linux.odin35
-rw-r--r--core/mem/virtual/virtual_linux.odin97
-rw-r--r--core/net/errors_linux.odin188
-rw-r--r--core/net/interface_linux.odin226
-rw-r--r--core/net/socket.odin2
-rw-r--r--core/net/socket_linux.odin466
-rw-r--r--core/os/os_linux.odin13
-rw-r--r--core/sync/futex_linux.odin99
-rw-r--r--core/sync/primitives_linux.odin4
-rw-r--r--core/sys/info/platform_linux.odin98
-rw-r--r--core/sys/linux/bits.odin1400
-rw-r--r--core/sys/linux/constants.odin199
-rw-r--r--core/sys/linux/helpers.odin150
-rw-r--r--core/sys/linux/sys.odin2038
-rw-r--r--core/sys/linux/syscall_amd64.odin373
-rw-r--r--core/sys/linux/syscall_arm32.odin470
-rw-r--r--core/sys/linux/syscall_arm64.odin321
-rw-r--r--core/sys/linux/syscall_i386.odin458
-rw-r--r--core/sys/linux/types.odin566
-rw-r--r--core/sys/linux/wrappers.odin121
-rw-r--r--core/time/tsc_linux.odin30
-rw-r--r--examples/all/all_linux.odin6
-rw-r--r--examples/all/all_vendor.odin19
-rw-r--r--examples/test-freestanding/main.odin30
25 files changed, 6690 insertions, 762 deletions
diff --git a/core/crypto/rand_linux.odin b/core/crypto/rand_linux.odin
index e5c194220..86fc425d6 100644
--- a/core/crypto/rand_linux.odin
+++ b/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:]
}
}
diff --git a/core/math/rand/system_linux.odin b/core/math/rand/system_linux.odin
index 2923b77be..42c9f86fa 100644
--- a/core/math/rand/system_linux.odin
+++ b/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
}
diff --git a/core/mem/virtual/virtual_linux.odin b/core/mem/virtual/virtual_linux.odin
index 0f376312f..7ffc7643e 100644
--- a/core/mem/virtual/virtual_linux.odin
+++ b/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)
}
diff --git a/core/net/errors_linux.odin b/core/net/errors_linux.odin
index d76132ad5..2370dd0d8 100644
--- a/core/net/errors_linux.odin
+++ b/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))
} \ No newline at end of file
diff --git a/core/net/interface_linux.odin b/core/net/interface_linux.odin
index e889cfa97..7c99cf23b 100644
--- a/core/net/interface_linux.odin
+++ b/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, {}
} \ No newline at end of file
diff --git a/core/net/socket.odin b/core/net/socket.odin
index 8cdf7cceb..40fa6ab56 100644
--- a/core/net/socket.odin
+++ b/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)
diff --git a/core/net/socket_linux.odin b/core/net/socket_linux.odin
index b7141e8ba..590946dff 100644
--- a/core/net/socket_linux.odin
+++ b/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
-}
diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin
index 51a14ab44..aabf42574 100644
--- a/core/os/os_linux.odin
+++ b/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
diff --git a/core/sync/futex_linux.odin b/core/sync/futex_linux.odin
index 947d61cdf..fe57c12ed 100644
--- a/core/sync/futex_linux.odin
+++ b/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")
}
diff --git a/core/sync/primitives_linux.odin b/core/sync/primitives_linux.odin
index 1e75891df..aa7a8b4b2 100644
--- a/core/sync/primitives_linux.odin
+++ b/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()
}
diff --git a/core/sys/info/platform_linux.odin b/core/sys/info/platform_linux.odin
index e9cc1dbc9..14961c2a8 100644
--- a/core/sys/info/platform_linux.odin
+++ b/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),
}
} \ No newline at end of file
diff --git a/core/sys/linux/bits.odin b/core/sys/linux/bits.odin
new file mode 100644
index 000000000..b6b22dfdb
--- /dev/null
+++ b/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
+
diff --git a/core/sys/linux/constants.odin b/core/sys/linux/constants.odin
new file mode 100644
index 000000000..f826a556d
--- /dev/null
+++ b/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)
+
diff --git a/core/sys/linux/helpers.odin b/core/sys/linux/helpers.odin
new file mode 100644
index 000000000..8fe4de6d2
--- /dev/null
+++ b/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)
+ }
+}
+
diff --git a/core/sys/linux/sys.odin b/core/sys/linux/sys.odin
new file mode 100644
index 000000000..fa7b7186a
--- /dev/null
+++ b/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
diff --git a/core/sys/linux/syscall_amd64.odin b/core/sys/linux/syscall_amd64.odin
new file mode 100644
index 000000000..ee4e16280
--- /dev/null
+++ b/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)
diff --git a/core/sys/linux/syscall_arm32.odin b/core/sys/linux/syscall_arm32.odin
new file mode 100644
index 000000000..74640a1a3
--- /dev/null
+++ b/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)
diff --git a/core/sys/linux/syscall_arm64.odin b/core/sys/linux/syscall_arm64.odin
new file mode 100644
index 000000000..61b5a31b7
--- /dev/null
+++ b/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)
+
+
diff --git a/core/sys/linux/syscall_i386.odin b/core/sys/linux/syscall_i386.odin
new file mode 100644
index 000000000..4609fc99c
--- /dev/null
+++ b/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)
diff --git a/core/sys/linux/types.odin b/core/sys/linux/types.odin
new file mode 100644
index 000000000..214aff9cf
--- /dev/null
+++ b/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,
+}
diff --git a/core/sys/linux/wrappers.odin b/core/sys/linux/wrappers.odin
new file mode 100644
index 000000000..a4c4aac32
--- /dev/null
+++ b/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)
+} \ No newline at end of file
diff --git a/core/time/tsc_linux.odin b/core/time/tsc_linux.odin
index c5f2902e9..77a79fe52 100644
--- a/core/time/tsc_linux.odin
+++ b/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
}
diff --git a/examples/all/all_linux.odin b/examples/all/all_linux.odin
new file mode 100644
index 000000000..18bba951c
--- /dev/null
+++ b/examples/all/all_linux.odin
@@ -0,0 +1,6 @@
+//+build linux
+package all
+
+import linux "core:sys/linux"
+
+_ :: linux \ No newline at end of file
diff --git a/examples/all/all_vendor.odin b/examples/all/all_vendor.odin
index fa1e8d995..9cc915778 100644
--- a/examples/all/all_vendor.odin
+++ b/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
diff --git a/examples/test-freestanding/main.odin b/examples/test-freestanding/main.odin
deleted file mode 100644
index 518e3d45e..000000000
--- a/examples/test-freestanding/main.odin
+++ /dev/null
@@ -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)
-}