Browse Source

sys/linux: fix some syscalls and types; add more to Sig_Action and Sig_Info; Pid int->i32

jason 1 year ago
parent
commit
f22754fc90
3 changed files with 182 additions and 76 deletions
  1. 75 40
      core/sys/linux/bits.odin
  2. 31 16
      core/sys/linux/sys.odin
  3. 76 20
      core/sys/linux/types.odin

+ 75 - 40
core/sys/linux/bits.odin

@@ -150,44 +150,66 @@ Errno :: enum i32 {
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	RDONLY flag is not present, because it has the value of 0, i.e. it is the
 	default, unless WRONLY or RDWR is specified.
 	default, unless WRONLY or RDWR is specified.
 */
 */
-Open_Flags_Bits :: enum {
-	WRONLY    = 0,
-	RDWR      = 1,
-	CREAT     = 6,
-	EXCL      = 7,
-	NOCTTY    = 8,
-	TRUNC     = 9,
-	APPEND    = 10,
-	NONBLOCK  = 11,
-	DSYNC     = 12,
-	ASYNC     = 13,
-	DIRECT    = 14,
-	LARGEFILE = 15,
-	DIRECTORY = 16,
-	NOFOLLOW  = 17,
-	NOATIME   = 18,
-	CLOEXEC   = 19,
-	PATH      = 21,
-}
-
-// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
-#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
-#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
-#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
-#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
-#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
-#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
-#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
-#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
-#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
-#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
-#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
-#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
-#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
-#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
-#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
-#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
-#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
+when ODIN_ARCH != .arm64 && ODIN_ARCH != .arm32 {
+	Open_Flags_Bits :: enum {
+		WRONLY    = 0,
+		RDWR      = 1,
+		CREAT     = 6,
+		EXCL      = 7,
+		NOCTTY    = 8,
+		TRUNC     = 9,
+		APPEND    = 10,
+		NONBLOCK  = 11,
+		DSYNC     = 12,
+		ASYNC     = 13,
+		DIRECT    = 14,
+		LARGEFILE = 15,
+		DIRECTORY = 16,
+		NOFOLLOW  = 17,
+		NOATIME   = 18,
+		CLOEXEC   = 19,
+		PATH      = 21,
+	}
+	// https://github.com/torvalds/linux/blob/7367539ad4b0f8f9b396baf02110962333719a48/include/uapi/asm-generic/fcntl.h#L19
+	#assert(1 << uint(Open_Flags_Bits.WRONLY)    == 0o0000000_1)
+	#assert(1 << uint(Open_Flags_Bits.RDWR)      == 0o0000000_2)
+	#assert(1 << uint(Open_Flags_Bits.CREAT)     == 0o00000_100)
+	#assert(1 << uint(Open_Flags_Bits.EXCL)      == 0o00000_200)
+	#assert(1 << uint(Open_Flags_Bits.NOCTTY)    == 0o00000_400)
+	#assert(1 << uint(Open_Flags_Bits.TRUNC)     == 0o0000_1000)
+	#assert(1 << uint(Open_Flags_Bits.APPEND)    == 0o0000_2000)
+	#assert(1 << uint(Open_Flags_Bits.NONBLOCK)  == 0o0000_4000)
+	#assert(1 << uint(Open_Flags_Bits.DSYNC)     == 0o000_10000)
+	#assert(1 << uint(Open_Flags_Bits.ASYNC)     == 0o000_20000)
+	#assert(1 << uint(Open_Flags_Bits.DIRECT)    == 0o000_40000)
+	#assert(1 << uint(Open_Flags_Bits.LARGEFILE) == 0o00_100000)
+	#assert(1 << uint(Open_Flags_Bits.DIRECTORY) == 0o00_200000)
+	#assert(1 << uint(Open_Flags_Bits.NOFOLLOW)  == 0o00_400000)
+	#assert(1 << uint(Open_Flags_Bits.NOATIME)   == 0o0_1000000)
+	#assert(1 << uint(Open_Flags_Bits.CLOEXEC)   == 0o0_2000000)
+	#assert(1 << uint(Open_Flags_Bits.PATH)      == 0o_10000000)
+
+} else {
+	Open_Flags_Bits :: enum {
+		WRONLY    = 0,
+		RDWR      = 1,
+		CREAT     = 6,
+		EXCL      = 7,
+		NOCTTY    = 8,
+		TRUNC     = 9,
+		APPEND    = 10,
+		NONBLOCK  = 11,
+		DSYNC     = 12,
+		ASYNC     = 13,
+		DIRECTORY = 14,
+		NOFOLLOW  = 15,
+		DIRECT    = 16,
+		LARGEFILE = 17,
+		NOATIME   = 18,
+		CLOEXEC   = 19,
+		PATH      = 21,
+	}
+}
 
 
 /*
 /*
 	Bits for FD_Flags bitset
 	Bits for FD_Flags bitset
@@ -867,7 +889,7 @@ Wait_Option :: enum {
 	WSTOPPED    = 1,
 	WSTOPPED    = 1,
 	WEXITED     = 2,
 	WEXITED     = 2,
 	WCONTINUED  = 3,
 	WCONTINUED  = 3,
-	WNOWAIT     = 24, 
+	WNOWAIT     = 24,
 	// // For processes created using clone
 	// // For processes created using clone
 	__WNOTHREAD = 29,
 	__WNOTHREAD = 29,
 	__WALL      = 30,
 	__WALL      = 30,
@@ -946,9 +968,22 @@ Sig_Stack_Flag :: enum i32 {
 	AUTODISARM = 31,
 	AUTODISARM = 31,
 }
 }
 
 
+Sig_Action_Flag :: enum u32 {
+	NOCLDSTOP      = 0,
+	NOCLDWAIT      = 1,
+	SIGINFO        = 2,
+	UNSUPPORTED    = 10,
+	EXPOSE_TAGBITS = 11,
+	RESTORER       = 26,
+	ONSTACK        = 27,
+	RESTART        = 28,
+	NODEFER        = 30,
+	RESETHAND      = 31,
+}
+
 /*
 /*
 	Type of socket to create
 	Type of socket to create
-    - For TCP you want to use SOCK_STREAM
+	- For TCP you want to use SOCK_STREAM
 	- For UDP you want to use SOCK_DGRAM
 	- For UDP you want to use SOCK_DGRAM
 	Also see `Protocol`
 	Also see `Protocol`
 */
 */

+ 31 - 16
core/sys/linux/sys.odin

@@ -69,7 +69,7 @@ close :: proc "contextless" (fd: Fd) -> (Errno) {
 stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) {
 stat :: proc "contextless" (filename: cstring, stat: ^Stat) -> (Errno) {
 	when size_of(int) == 8 {
 	when size_of(int) == 8 {
 		when ODIN_ARCH == .arm64 {
 		when ODIN_ARCH == .arm64 {
-			ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat)
+			ret := syscall(SYS_fstatat, AT_FDCWD, cast(rawptr) filename, stat, 0)
 			return Errno(-ret)
 			return Errno(-ret)
 		} else {
 		} else {
 			ret := syscall(SYS_stat, cast(rawptr) filename, stat)
 			ret := syscall(SYS_stat, cast(rawptr) filename, stat)
@@ -200,10 +200,25 @@ brk :: proc "contextless" (addr: uintptr) -> (Errno) {
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
 
 
+/*
+	Returns from signal handlers on some archs.
+*/
+rt_sigreturn :: proc "c" () -> ! {
+	intrinsics.syscall(uintptr(SYS_rt_sigreturn))
+	unreachable()
+}
+
 /*
 /*
 	Alter an action taken by a process.
 	Alter an action taken by a process.
 */
 */
-rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action, old_sigaction: ^Sig_Action) -> Errno {
+rt_sigaction :: proc "contextless" (sig: Signal, sigaction: ^Sig_Action($T), old_sigaction: ^Sig_Action) -> Errno {
+	// NOTE(jason): It appears that the restorer is required for i386 and amd64
+	when ODIN_ARCH == .i386 || ODIN_ARCH == .amd64 {
+		sigaction.flags += {.RESTORER}
+	}
+	if sigaction != nil && sigaction.restorer == nil && .RESTORER in sigaction.flags {
+		sigaction.restorer = rt_sigreturn
+	}
 	ret := syscall(SYS_rt_sigaction, sig, sigaction, old_sigaction, size_of(Sig_Set))
 	ret := syscall(SYS_rt_sigaction, sig, sigaction, old_sigaction, size_of(Sig_Set))
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
@@ -1123,7 +1138,7 @@ ftruncate :: proc "contextless" (fd: Fd, length: i64) -> (Errno) {
 		ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
 		ret := syscall(SYS_ftruncate64, fd, compat64_arg_pair(length))
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
-		ret := syscall(SYS_truncate, fd, compat64_arg_pair(length))
+		ret := syscall(SYS_ftruncate, fd, compat64_arg_pair(length))
 		return Errno(-ret)
 		return Errno(-ret)
 	}
 	}
 }
 }
@@ -1231,7 +1246,7 @@ creat :: proc "contextless" (name: cstring, mode: Mode) -> (Fd, Errno) {
 */
 */
 link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
 link :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
 	when ODIN_ARCH == .arm64 {
 	when ODIN_ARCH == .arm64 {
-		ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath)
+		ret := syscall(SYS_linkat, AT_FDCWD, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath, 0)
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
 		ret := syscall(SYS_link, cast(rawptr) target, cast(rawptr) linkpath)
 		ret := syscall(SYS_link, cast(rawptr) target, cast(rawptr) linkpath)
@@ -1261,7 +1276,7 @@ unlink :: proc "contextless" (name: cstring) -> (Errno) {
 */
 */
 symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
 symlink :: proc "contextless" (target: cstring, linkpath: cstring) -> (Errno) {
 	when ODIN_ARCH == .arm64 {
 	when ODIN_ARCH == .arm64 {
-		ret := syscall(SYS_symlinkat, AT_FDCWD, cast(rawptr) target, cast(rawptr) linkpath)
+		ret := syscall(SYS_symlinkat, cast(rawptr) target, AT_FDCWD, cast(rawptr) linkpath)
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
 		ret := syscall(SYS_symlink, cast(rawptr) target, cast(rawptr) linkpath)
 		ret := syscall(SYS_symlink, cast(rawptr) target, cast(rawptr) linkpath)
@@ -1291,7 +1306,7 @@ readlink :: proc "contextless" (name: cstring, buf: []u8) -> (int, Errno) {
 */
 */
 chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) {
 chmod :: proc "contextless" (name: cstring, mode: Mode) -> (Errno) {
 	when ODIN_ARCH == .arm64 {
 	when ODIN_ARCH == .arm64 {
-		ret := syscall(SYS_fchmodat, cast(rawptr) name, transmute(u32) mode, 0)
+		ret := syscall(SYS_fchmodat, AT_FDCWD, cast(rawptr) name, transmute(u32) mode)
 		return Errno(-ret)
 		return Errno(-ret)
 	} else {
 	} else {
 		ret := syscall(SYS_chmod, cast(rawptr) name, transmute(u32) mode)
 		ret := syscall(SYS_chmod, cast(rawptr) name, transmute(u32) mode)
@@ -2476,8 +2491,8 @@ tgkill :: proc "contextless" (tgid, tid: Pid, sig: Signal) -> (Errno) {
 	Wait on process, process group or pid file descriptor.
 	Wait on process, process group or pid file descriptor.
 	Available since Linux 2.6.10.
 	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)
+waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, options: Wait_Options, rusage: ^RUsage) -> (Errno) {
+	ret := syscall(SYS_waitid, id_type, id, sig_info, transmute(i32) options, rusage)
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
 
 
@@ -2504,7 +2519,7 @@ waitid :: proc "contextless" (id_type: Id_Type, id: Id, sig_info: ^Sig_Info, opt
 	Available since Linux 2.6.16.
 	Available since Linux 2.6.16.
 */
 */
 openat :: proc "contextless" (fd: Fd, name: cstring, flags: Open_Flags, mode: Mode = {}) -> (Fd, Errno) {
 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)
+	ret := syscall(SYS_openat, fd, transmute(uintptr) name, transmute(u32) flags, transmute(u32) mode)
 	return errno_unwrap(ret, Fd)
 	return errno_unwrap(ret, Fd)
 }
 }
 
 
@@ -2583,8 +2598,8 @@ linkat :: proc "contextless" (target_dirfd: Fd, oldpath: cstring, link_dirfd: Fd
 	Create a symbolic link at specified dirfd.
 	Create a symbolic link at specified dirfd.
 	Available since Linux 2.6.16.
 	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)
+symlinkat :: proc "contextless" (target: cstring, dirfd: Fd, linkpath: cstring) -> (Errno) {
+	ret := syscall(SYS_symlinkat, cast(rawptr) target, dirfd, cast(rawptr) linkpath)
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
 
 
@@ -2619,13 +2634,13 @@ faccessat :: proc "contextless" (dirfd: Fd, name: cstring, mode: Mode = F_OK) ->
 	Wait for events on a file descriptor.
 	Wait for events on a file descriptor.
 	Available since Linux 2.6.16.
 	Available since Linux 2.6.16.
 */
 */
-ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (Errno) {
+ppoll :: proc "contextless" (fds: []Poll_Fd, timeout: ^Time_Spec, sigmask: ^Sig_Set) -> (i32, Errno) {
 	when size_of(int) == 8 {
 	when size_of(int) == 8 {
 		ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
 		ret := syscall(SYS_ppoll, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
-		return Errno(-ret)
+		return errno_unwrap(ret, i32)
 	} else {
 	} else {
 		ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
 		ret := syscall(SYS_ppoll_time64, raw_data(fds), len(fds), timeout, sigmask, size_of(Sig_Set))
-		return Errno(-ret)
+		return errno_unwrap(ret, i32)
 	}
 	}
 }
 }
 
 
@@ -2808,8 +2823,8 @@ getrandom :: proc "contextless" (buf: []u8, flags: Get_Random_Flags) -> (int, Er
 	Execute program relative to a directory file descriptor.
 	Execute program relative to a directory file descriptor.
 	Available since Linux 3.19.
 	Available since Linux 3.19.
 */
 */
-execveat :: proc "contextless" (dirfd: Fd, name: cstring, argv: [^]cstring, envp: [^]cstring) -> (Errno) {
-	ret := syscall(SYS_execveat, dirfd, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp)
+execveat :: proc "contextless" (dirfd: Fd, name: cstring, argv: [^]cstring, envp: [^]cstring, flags: FD_Flags = {}) -> (Errno) {
+	ret := syscall(SYS_execveat, dirfd, cast(rawptr) name, cast(rawptr) argv, cast(rawptr) envp, transmute(i32) flags)
 	return Errno(-ret)
 	return Errno(-ret)
 }
 }
 
 

+ 76 - 20
core/sys/linux/types.odin

@@ -18,7 +18,7 @@ Gid :: distinct u32
 /*
 /*
 	Type for Process IDs, Thread IDs, Thread group ID.
 	Type for Process IDs, Thread IDs, Thread group ID.
 */
 */
-Pid :: distinct int
+Pid :: distinct i32
 
 
 /*
 /*
 	Type for any of: pid, pidfd, pgid.
 	Type for any of: pid, pidfd, pgid.
@@ -89,11 +89,11 @@ FD_Flags :: bit_set[FD_Flags_Bits; i32]
 	Represents file's permission and status bits
 	Represents file's permission and status bits
 **Example:**
 **Example:**
 	When you're passing a value of this type the recommended usage is:
 	When you're passing a value of this type the recommended usage is:
-	
+
 	```
 	```
 	  linux.Mode{.S_IXOTH, .S_IROTH} | linux.S_IRWXU | linux.S_IRWXG
 	  linux.Mode{.S_IXOTH, .S_IROTH} | linux.S_IRWXU | linux.S_IRWXG
 	```
 	```
-	  
+
 	This would generate a mode that has full permissions for the
 	This would generate a mode that has full permissions for the
 	file's owner and group, and only "read" and "execute" bits
 	file's owner and group, and only "read" and "execute" bits
 	for others.
 	for others.
@@ -151,9 +151,9 @@ when ODIN_ARCH == .amd64 {
 		size:       i64,
 		size:       i64,
 		blksize:    uint,
 		blksize:    uint,
 		blocks:     u64,
 		blocks:     u64,
-		atim:       Time_Spec,
-		mtim:       Time_Spec,
-		ctim:       Time_Spec,
+		atime:      Time_Spec,
+		mtime:      Time_Spec,
+		ctime:      Time_Spec,
 		ino:        Inode,
 		ino:        Inode,
 	}
 	}
 }
 }
@@ -495,16 +495,15 @@ Pid_FD_Flags :: bit_set[Pid_FD_Flags_Bits; i32]
 //  1. Odin's bitfields start from 0, whereas signals start from 1
 //  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?).
 //  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.
 //     it makes a difference because ARM is big endian.
-@private _SIGSET_NWORDS :: (1024 / (8 * size_of(uint)))
+@private _SIGSET_NWORDS :: (8 / size_of(uint))
 Sig_Set :: [_SIGSET_NWORDS]uint
 Sig_Set :: [_SIGSET_NWORDS]uint
 
 
 @private SI_MAX_SIZE       :: 128
 @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)
+@private SI_ARCH_PREAMBLE  :: 4 * size_of(i32)
+@private SI_PAD_SIZE       :: SI_MAX_SIZE - SI_ARCH_PREAMBLE
 
 
 Sig_Handler_Fn :: #type proc "c" (sig: Signal)
 Sig_Handler_Fn :: #type proc "c" (sig: Signal)
-Sig_Restore_Fn :: #type proc "c" ()
+Sig_Restore_Fn :: #type proc "c" () -> !
 
 
 Sig_Info :: struct #packed {
 Sig_Info :: struct #packed {
 	signo: Signal,
 	signo: Signal,
@@ -518,8 +517,9 @@ Sig_Info :: struct #packed {
 			uid: Uid, /* sender's uid */
 			uid: Uid, /* sender's uid */
 		},
 		},
 		using _timer: struct {
 		using _timer: struct {
-			timerid: i32,       /* timer id */
+			timerid: i32,   /* timer id */
 			overrun: i32,   /* overrun count */
 			overrun: i32,   /* overrun count */
+			value: Sig_Val, /* timer value */
 		},
 		},
 		/* POSIX.1b signals */
 		/* POSIX.1b signals */
 		using _rt: struct {
 		using _rt: struct {
@@ -528,8 +528,8 @@ Sig_Info :: struct #packed {
 		},
 		},
 		/* SIGCHLD */
 		/* SIGCHLD */
 		using _sigchld: struct {
 		using _sigchld: struct {
-			_pid1: Pid,      /* which child */
-			_uid1: Uid,      /* sender's uid */
+			_pid1: Pid,  /* which child */
+			_uid1: Uid,  /* sender's uid */
 			status: i32, /* exit code */
 			status: i32, /* exit code */
 			utime: uint,
 			utime: uint,
 			stime: uint, //clock_t
 			stime: uint, //clock_t
@@ -537,7 +537,24 @@ Sig_Info :: struct #packed {
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
 		/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
 		using _sigfault: struct {
 		using _sigfault: struct {
 			addr: rawptr, /* faulting insn/memory ref. */
 			addr: rawptr, /* faulting insn/memory ref. */
-			addr_lsb: i16, /* LSB of the reported address */
+			using _: struct #raw_union {
+				trapno: i32,   /* Trap number that caused signal */
+				addr_lsb: i16, /* LSB of the reported address */
+				using _addr_bnd: struct {
+					_pad2: u64,
+					lower: rawptr, /* lower bound during fault */
+					upper: rawptr, /* upper bound during fault */
+				},
+				using _addr_pkey: struct {
+					_pad3: u64,
+					pkey: u32, /* protection key on PTE that faulted */
+				},
+				using _perf: struct {
+					perf_data: u64,
+					perf_type: u32,
+					perf_flags: u32,
+				},
+			},
 		},
 		},
 		/* SIGPOLL */
 		/* SIGPOLL */
 		using _sigpoll: struct {
 		using _sigpoll: struct {
@@ -547,12 +564,43 @@ Sig_Info :: struct #packed {
 		/* SIGSYS */
 		/* SIGSYS */
 		using _sigsys: struct {
 		using _sigsys: struct {
 			call_addr: rawptr, /* calling user insn */
 			call_addr: rawptr, /* calling user insn */
-			syscall: i32,    /* triggering system call number */
-			arch: u32,      /* AUDIT_ARCH_* of syscall */
+			syscall: i32,      /* triggering system call number */
+			arch: u32,         /* AUDIT_ARCH_* of syscall */
 		},
 		},
 	},
 	},
 }
 }
 
 
+#assert(size_of(Sig_Info) == 128)
+when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 {
+	#assert(offset_of(Sig_Info, signo)      == 0x00)
+	#assert(offset_of(Sig_Info, errno)      == 0x04)
+	#assert(offset_of(Sig_Info, code)       == 0x08)
+	#assert(offset_of(Sig_Info, pid)        == 0x10)
+	#assert(offset_of(Sig_Info, uid)        == 0x14)
+	#assert(offset_of(Sig_Info, timerid)    == 0x10)
+	#assert(offset_of(Sig_Info, overrun)    == 0x14)
+	#assert(offset_of(Sig_Info, value)      == 0x18)
+	#assert(offset_of(Sig_Info, status)     == 0x18)
+	#assert(offset_of(Sig_Info, utime)      == 0x20)
+	#assert(offset_of(Sig_Info, stime)      == 0x28)
+	#assert(offset_of(Sig_Info, addr)       == 0x10)
+	#assert(offset_of(Sig_Info, addr_lsb)   == 0x18)
+	#assert(offset_of(Sig_Info, trapno)     == 0x18)
+	#assert(offset_of(Sig_Info, lower)      == 0x20)
+	#assert(offset_of(Sig_Info, upper)      == 0x28)
+	#assert(offset_of(Sig_Info, pkey)       == 0x20)
+	#assert(offset_of(Sig_Info, perf_data)  == 0x18)
+	#assert(offset_of(Sig_Info, perf_type)  == 0x20)
+	#assert(offset_of(Sig_Info, perf_flags) == 0x24)
+	#assert(offset_of(Sig_Info, band)       == 0x10)
+	#assert(offset_of(Sig_Info, fd)         == 0x18)
+	#assert(offset_of(Sig_Info, call_addr)  == 0x10)
+	#assert(offset_of(Sig_Info, syscall)    == 0x18)
+	#assert(offset_of(Sig_Info, arch)       == 0x1C)
+} else {
+	// TODO
+}
+
 SIGEV_MAX_SIZE :: 64
 SIGEV_MAX_SIZE :: 64
 SIGEV_PAD_SIZE :: ((SIGEV_MAX_SIZE-size_of(i32)*2+size_of(Sig_Val))/size_of(i32))
 SIGEV_PAD_SIZE :: ((SIGEV_MAX_SIZE-size_of(i32)*2+size_of(Sig_Val))/size_of(i32))
 
 
@@ -583,12 +631,20 @@ Sig_Stack :: struct {
 	size: uintptr,
 	size: uintptr,
 }
 }
 
 
+Sig_Action_Special :: enum uint {
+	SIG_DFL = 0,
+	SIG_IGN = 1,
+	SIG_ERR = ~uint(0),
+}
+
+Sig_Action_Flags :: bit_set[Sig_Action_Flag; uint]
 Sig_Action :: struct($T: typeid) {
 Sig_Action :: struct($T: typeid) {
 	using _u: struct #raw_union {
 	using _u: struct #raw_union {
 		handler: Sig_Handler_Fn,
 		handler: Sig_Handler_Fn,
 		sigaction: #type proc "c" (sig: Signal, si: ^Sig_Info, ctx: ^T),
 		sigaction: #type proc "c" (sig: Signal, si: ^Sig_Info, ctx: ^T),
+		special: Sig_Action_Special,
 	},
 	},
-	flags: uint,
+	flags: Sig_Action_Flags,
 	restorer: Sig_Restore_Fn,
 	restorer: Sig_Restore_Fn,
 	mask: Sig_Set,
 	mask: Sig_Set,
 }
 }
@@ -733,7 +789,7 @@ RLimit :: struct {
 
 
 /*
 /*
 	Structure representing how much of each resource got used.
 	Structure representing how much of each resource got used.
-*/	
+*/
 RUsage :: struct {
 RUsage :: struct {
 	utime:         Time_Val,
 	utime:         Time_Val,
 	stime:         Time_Val,
 	stime:         Time_Val,
@@ -813,7 +869,7 @@ when size_of(int) == 8 || ODIN_ARCH == .i386 {
 		cpid:       Pid,
 		cpid:       Pid,
 		lpid:       Pid,
 		lpid:       Pid,
 		nattach:    uint,
 		nattach:    uint,
-		_:          [2]uint,        
+		_:          [2]uint,
 	}
 	}
 }
 }