mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
121 lines
4.1 KiB
Odin
121 lines
4.1 KiB
Odin
//+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)
|
|
} |