lx 0.4.0

A no_std crate to use Linux system calls
Documentation
use core::{
    arch::asm,
    mem,
};

use crate::{
    pid_t,
    result_from_value,
};

pub const CLONE_NEWTIME: u32 = 0x80;
pub const CLONE_VM: u32 = 0x100;
pub const CLONE_FS: u32 = 0x200;
pub const CLONE_FILES: u32 = 0x400;
pub const CLONE_SIGHAND: u32 = 0x800;
pub const CLONE_PIDFD: u32 = 0x1000;
pub const CLONE_PTRACE: u32 = 0x2000;
pub const CLONE_VFORK: u32 = 0x4000;
pub const CLONE_PARENT: u32 = 0x8000;
pub const CLONE_THREAD: u32 = 0x10000;
pub const CLONE_NEWNS: u32 = 0x20000;
pub const CLONE_SYSVSEM: u32 = 0x40000;
pub const CLONE_SETTLS: u32 = 0x80000;
pub const CLONE_PARENT_SETTID: u32 = 0x100000;
pub const CLONE_CHILD_CLEARTID: u32 = 0x200000;
pub const CLONE_DETACHED: u32 = 0x400000;
pub const CLONE_UNTRACED: u32 = 0x800000;
pub const CLONE_CHILD_SETTID: u32 = 0x1000000;
pub const CLONE_NEWCGROUP: u32 = 0x2000000;
pub const CLONE_NEWUTS: u32 = 0x4000000;
pub const CLONE_NEWIPC: u32 = 0x8000000;
pub const CLONE_NEWUSER: u32 = 0x10000000;
pub const CLONE_NEWPID: u32 = 0x20000000;
pub const CLONE_NEWNET: u32 = 0x40000000;
pub const CLONE_IO: u32 = 0x80000000;

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct clone_args {
    pub flags: u64,
    pub pidfd: u64,
    pub child_tid: u64,
    pub parent_tid: u64,
    pub exit_signal: u64,
    pub stack: u64,
    pub stack_size: u64,
    pub tls: u64,
    pub set_tid: u64,
    pub set_tid_size: u64,
    pub cgroup: u64,
}

#[inline]
#[allow(clippy::missing_safety_doc)]
pub unsafe fn clone(
    flags: u32,
    sp: *mut u8,
    tid_parent: *mut i32,
    tid_child: *mut i32,
    tls: *mut u8,
    cb: unsafe fn(user_data: usize) -> !,
    user_data: usize,
) -> crate::Result<pid_t> {
    let ret: i32;
    asm!(
        "syscall",
        // If we are the new thread...
        "test rax, rax",
        "jnz 1f",
        // Mark the new outer frame.
        "xor ebp, ebp",
        // Call `f`.
        "mov rdi, r12",
        "call r9",
        "1:",
        // Registers we use in the new thread.
        in("r9") cb,
        in("r12") user_data,
        // System call parameters.
        in("rax") 56,
        in("rdi") flags,
        in("rsi") sp,
        in("rdx") tid_parent,
        in("r10") tid_child,
        in("r8") tls,
        lateout("eax") ret,
        out("rcx") _,
        out("r11") _,
    );
    result_from_value(ret)
}

#[inline]
#[allow(clippy::missing_safety_doc)]
pub unsafe fn clone3(
    args: &mut clone_args,
    cb: unsafe fn(user_data: usize) -> !,
    user_data: usize,
) -> crate::Result<pid_t> {
    let ret: i32;
    asm!(
        "syscall",
        // If we are the new thread...
        "test rax, rax",
        "jnz 1f",
        // Mark the new outer frame.
        "xor ebp, ebp",
        // Call `f`.
        "mov rdi, r10",
        "call rdx",
        "1:",
        // Registers we use in the new thread.
        in("rdx") cb,
        in("r10") user_data,
        // System call parameters.
        in("rax") 435,
        in("rdi") args as *mut clone_args,
        in("rsi") mem::size_of_val(args),
        lateout("eax") ret,
        out("rcx") _,
        out("r11") _,
    );
    result_from_value(ret)
}