1use core::num::NonZero;
2
3use safa_abi::{
4 errors::ErrorStatus,
5 ffi::{
6 num::ShouldNotBeZero,
7 option::{COption, OptZero},
8 ptr::FFINonNull,
9 slice::Slice,
10 str::Str,
11 },
12 process::{ProcessStdio, RawContextPriority, RawPSpawnConfig, SpawnFlags},
13};
14
15use crate::{
16 exported_func,
17 process::stdio::{systry_get_stderr, systry_get_stdin, systry_get_stdout},
18 syscalls::types::{OptionalPtrMut, Pid, RequiredPtr, RequiredPtrMut, Ri, SyscallResult},
19};
20
21use super::{define_syscall, SyscallNum};
22
23#[cfg(not(feature = "rustc-dep-of-std"))]
24extern crate alloc;
25use alloc::vec::Vec;
26
27define_syscall! {
28 SyscallNum::SysPExit => {
29 sysp_exit(code: usize) unreachable
31 },
32 SyscallNum::SysPWait => {
33 sysp_wait(pid: Pid, exit_code: OptionalPtrMut<usize>)
42 },
43 SyscallNum::SysPTryCleanUp => {
44 sysp_try_cleanup(pid: Pid, dest_exit_code: OptionalPtrMut<usize>)
51 },
52 SyscallNum::SysPSpawn => {
53 sysp_spawn_inner(path: Str, raw_config: RequiredPtr<RawPSpawnConfig>, dest_pid: OptionalPtrMut<Pid>)
54 }
55}
56
57#[inline]
59pub fn exit(code: usize) -> ! {
60 sysp_exit(code)
61}
62
63#[inline]
64pub fn wait(pid: Pid) -> Result<usize, ErrorStatus> {
73 let mut dest_exit_code = 0;
74 let ptr = RequiredPtrMut::new(&mut dest_exit_code).into();
75 err_from_u16!(sysp_wait(pid, ptr), dest_exit_code)
76}
77#[inline]
78pub fn try_cleanup(pid: Pid) -> Result<Option<usize>, ErrorStatus> {
85 let mut dest_exit_code = 0;
86 let ptr = RequiredPtrMut::new(&mut dest_exit_code).into();
87 let results = err_from_u16!(sysp_try_cleanup(pid, ptr), dest_exit_code);
88
89 match results {
90 Ok(results) => Ok(Some(results)),
91 Err(ErrorStatus::Generic) => Ok(None),
92 Err(e) => Err(e),
93 }
94}
95
96exported_func! {
97 extern "C" fn sysp_spawn(
109 name: OptZero<Str>,
110 path: Str,
111 args: OptZero<Slice<Str>>,
112 flags: SpawnFlags,
114 priority: RawContextPriority,
115 stdin: COption<Ri>,
117 stdout: COption<Ri>,
118 stderr: COption<Ri>,
119 custom_stack_size: OptZero<ShouldNotBeZero<usize>>,
120 dest_pid: OptionalPtrMut<Pid>,
121 ) -> SyscallResult {
122 let (stdin, stdout, stderr): (Option<_>, Option<_>, Option<_>) =
123 (stdin.into(), stdout.into(), stderr.into());
124
125 let stdio = {
126 if stdin.is_none() && stdout.is_none() && stderr.is_none() {
127 None
128 } else {
129 let stdout = stdout.or(systry_get_stdout().into());
130 let stdin = stdin.or(systry_get_stdin().into());
131 let stderr = stderr.or(systry_get_stderr().into());
132
133 Some(ProcessStdio::new(stdout, stdin, stderr))
134 }
135 };
136
137 let stdio = stdio.as_ref();
138 let stdio_ptr = stdio.map(|m| unsafe {FFINonNull::new_unchecked(m as *const _ as *mut _)}).into();
139
140 let (_, mut env) = unsafe { crate::process::env::duplicate_env() };
141
142 let env = unsafe {OptZero::some(Slice::from_raw_parts(env.as_mut_ptr(), env.len()))};
143 let config = RawPSpawnConfig::new_from_raw(name, args, env, flags, stdio_ptr, priority, custom_stack_size);
144
145 let raw_config_ptr = unsafe {RequiredPtr::new_unchecked(&config as *const _ as *mut _) };
146 sysp_spawn_inner(path, raw_config_ptr, dest_pid)
147 }
148}
149
150#[inline]
160pub unsafe fn unsafe_spawn(
161 name: Option<&str>,
162 path: &str,
163 args: *mut [&str],
164 flags: SpawnFlags,
165 priority: RawContextPriority,
166 stdin: Option<Ri>,
167 stdout: Option<Ri>,
168 stderr: Option<Ri>,
169 custom_stack_size: Option<NonZero<usize>>,
170) -> Result<Pid, ErrorStatus> {
171 let mut pid = 0;
172 let pid_ptr = RequiredPtrMut::new(&mut pid).into();
173
174 let name = name.map(|s| Str::from_str(s)).into();
175 let path = Str::from_str(path);
176 let args = unsafe { OptZero::some(Slice::from_str_slices_mut(args as *mut [*mut str])) };
177
178 err_from_u16!(
179 sysp_spawn(
180 name,
181 path,
182 args,
183 flags,
184 priority.into(),
185 stdin.into(),
186 stdout.into(),
187 stderr.into(),
188 match custom_stack_size {
189 None => OptZero::none(),
190 Some(size) => OptZero::some(unsafe { ShouldNotBeZero::new_unchecked(size.get()) }),
191 },
192 pid_ptr,
193 ),
194 pid
195 )
196}
197
198#[inline]
206pub fn spawn(
207 name: Option<&str>,
208 path: &str,
209 mut argv: Vec<&str>,
210 flags: SpawnFlags,
211 priority: RawContextPriority,
212 stdin: Option<Ri>,
213 stdout: Option<Ri>,
214 stderr: Option<Ri>,
215 custom_stack_size: Option<NonZero<usize>>,
216) -> Result<Pid, ErrorStatus> {
217 let argv: &mut [&str] = &mut argv;
218 unsafe {
219 unsafe_spawn(
220 name,
221 path,
222 argv as *mut _,
223 flags,
224 priority,
225 stdin,
226 stdout,
227 stderr,
228 custom_stack_size,
229 )
230 }
231}