use core::num::NonZero;
use safa_abi::{
errors::ErrorStatus,
ffi::{
num::ShouldNotBeZero,
option::{COption, OptZero},
ptr::FFINonNull,
slice::Slice,
str::Str,
},
process::{ProcessStdio, RawContextPriority, RawPSpawnConfig, SpawnFlags},
};
use crate::{
exported_func,
process::stdio::{systry_get_stderr, systry_get_stdin, systry_get_stdout},
syscalls::types::{OptionalPtrMut, Pid, RequiredPtr, RequiredPtrMut, Ri, SyscallResult},
};
use super::{define_syscall, SyscallNum};
#[cfg(not(feature = "rustc-dep-of-std"))]
extern crate alloc;
use alloc::vec::Vec;
define_syscall! {
SyscallNum::SysPExit => {
sysp_exit(code: usize) unreachable
},
SyscallNum::SysPWait => {
sysp_wait(pid: Pid, exit_code: OptionalPtrMut<usize>)
},
SyscallNum::SysPTryCleanUp => {
sysp_try_cleanup(pid: Pid, dest_exit_code: OptionalPtrMut<usize>)
},
SyscallNum::SysPSpawn => {
sysp_spawn_inner(path: Str, raw_config: RequiredPtr<RawPSpawnConfig>, dest_pid: OptionalPtrMut<Pid>)
}
}
#[inline]
pub fn exit(code: usize) -> ! {
sysp_exit(code)
}
#[inline]
pub fn wait(pid: Pid) -> Result<usize, ErrorStatus> {
let mut dest_exit_code = 0;
let ptr = RequiredPtrMut::new(&mut dest_exit_code).into();
err_from_u16!(sysp_wait(pid, ptr), dest_exit_code)
}
#[inline]
pub fn try_cleanup(pid: Pid) -> Result<Option<usize>, ErrorStatus> {
let mut dest_exit_code = 0;
let ptr = RequiredPtrMut::new(&mut dest_exit_code).into();
let results = err_from_u16!(sysp_try_cleanup(pid, ptr), dest_exit_code);
match results {
Ok(results) => Ok(Some(results)),
Err(ErrorStatus::Generic) => Ok(None),
Err(e) => Err(e),
}
}
exported_func! {
extern "C" fn sysp_spawn(
name: OptZero<Str>,
path: Str,
args: OptZero<Slice<Str>>,
flags: SpawnFlags,
priority: RawContextPriority,
stdin: COption<Ri>,
stdout: COption<Ri>,
stderr: COption<Ri>,
custom_stack_size: OptZero<ShouldNotBeZero<usize>>,
dest_pid: OptionalPtrMut<Pid>,
) -> SyscallResult {
let (stdin, stdout, stderr): (Option<_>, Option<_>, Option<_>) =
(stdin.into(), stdout.into(), stderr.into());
let stdio = {
if stdin.is_none() && stdout.is_none() && stderr.is_none() {
None
} else {
let stdout = stdout.or(systry_get_stdout().into());
let stdin = stdin.or(systry_get_stdin().into());
let stderr = stderr.or(systry_get_stderr().into());
Some(ProcessStdio::new(stdout, stdin, stderr))
}
};
let stdio = stdio.as_ref();
let stdio_ptr = stdio.map(|m| unsafe {FFINonNull::new_unchecked(m as *const _ as *mut _)}).into();
let (_, mut env) = unsafe { crate::process::env::duplicate_env() };
let env = unsafe {OptZero::some(Slice::from_raw_parts(env.as_mut_ptr(), env.len()))};
let config = RawPSpawnConfig::new_from_raw(name, args, env, flags, stdio_ptr, priority, custom_stack_size);
let raw_config_ptr = unsafe {RequiredPtr::new_unchecked(&config as *const _ as *mut _) };
sysp_spawn_inner(path, raw_config_ptr, dest_pid)
}
}
#[inline]
pub unsafe fn unsafe_spawn(
name: Option<&str>,
path: &str,
args: *mut [&str],
flags: SpawnFlags,
priority: RawContextPriority,
stdin: Option<Ri>,
stdout: Option<Ri>,
stderr: Option<Ri>,
custom_stack_size: Option<NonZero<usize>>,
) -> Result<Pid, ErrorStatus> {
let mut pid = 0;
let pid_ptr = RequiredPtrMut::new(&mut pid).into();
let name = name.map(|s| Str::from_str(s)).into();
let path = Str::from_str(path);
let args = unsafe { OptZero::some(Slice::from_str_slices_mut(args as *mut [*mut str])) };
err_from_u16!(
sysp_spawn(
name,
path,
args,
flags,
priority.into(),
stdin.into(),
stdout.into(),
stderr.into(),
match custom_stack_size {
None => OptZero::none(),
Some(size) => OptZero::some(unsafe { ShouldNotBeZero::new_unchecked(size.get()) }),
},
pid_ptr,
),
pid
)
}
#[inline]
pub fn spawn(
name: Option<&str>,
path: &str,
mut argv: Vec<&str>,
flags: SpawnFlags,
priority: RawContextPriority,
stdin: Option<Ri>,
stdout: Option<Ri>,
stderr: Option<Ri>,
custom_stack_size: Option<NonZero<usize>>,
) -> Result<Pid, ErrorStatus> {
let argv: &mut [&str] = &mut argv;
unsafe {
unsafe_spawn(
name,
path,
argv as *mut _,
flags,
priority,
stdin,
stdout,
stderr,
custom_stack_size,
)
}
}