safa_api/process/
stdio.rs

1//! contains functions related to standard input/output/error streams descriptors
2//! api must be initialized before using these functions, see [`super::init`]
3
4use core::{cell::UnsafeCell, mem::MaybeUninit};
5
6use crate::{
7    exported_func,
8    syscalls::{self},
9};
10use safa_abi::{
11    ffi::option::COption,
12    process::{AbiStructures, ProcessStdio},
13};
14
15use crate::sync::cell::LazyCell;
16
17pub(super) struct StaticAbiStructures(UnsafeCell<MaybeUninit<AbiStructures>>);
18
19impl StaticAbiStructures {
20    pub unsafe fn init(&self, structures: AbiStructures) {
21        let ptr = self.0.get();
22        ptr.write(MaybeUninit::new(structures));
23    }
24
25    unsafe fn get(&'static self) -> &'static AbiStructures {
26        let ptr = self.0.get();
27        MaybeUninit::assume_init_ref(&*ptr)
28    }
29}
30
31unsafe impl Sync for StaticAbiStructures {}
32
33pub(super) static ABI_STRUCTURES: StaticAbiStructures =
34    StaticAbiStructures(UnsafeCell::new(MaybeUninit::zeroed()));
35
36static STDIO: LazyCell<ProcessStdio> = LazyCell::new(|| unsafe { ABI_STRUCTURES.get().stdio });
37static STDIN: LazyCell<usize> = LazyCell::new(|| {
38    let stdin: Option<usize> = STDIO.stdin.into();
39    if let Some(stdin) = stdin {
40        stdin
41    } else {
42        syscalls::fs::open_all("dev:/tty").expect("failed to fall back to `dev:/tty` for stdin")
43    }
44});
45
46static STDOUT: LazyCell<usize> = LazyCell::new(|| {
47    let stdout: Option<usize> = STDIO.stdout.into();
48    if let Some(stdout) = stdout {
49        stdout
50    } else {
51        syscalls::fs::open_all("dev:/tty").expect("failed to fall back to `dev:/tty` for stdout")
52    }
53});
54
55static STDERR: LazyCell<usize> = LazyCell::new(|| {
56    let stderr: Option<usize> = STDIO.stderr.into();
57    if let Some(stderr) = stderr {
58        stderr
59    } else {
60        syscalls::fs::open_all("dev:/tty").expect("failed to fall back to `dev:/tty` for stderr")
61    }
62});
63
64exported_func! {
65    /// Returns the resource id of the stdout file descriptor (if available)
66    pub extern "C" fn systry_get_stdout() -> COption<usize> {
67        STDIO.stdout.clone()
68    }
69}
70
71exported_func! {
72    /// Returns the resource id of the stderr file descriptor (if available)
73    pub extern "C" fn systry_get_stderr() -> COption<usize> {
74        STDIO.stderr.clone()
75    }
76}
77
78exported_func! {
79    /// Returns the resource id of the stdin file descriptor (if available)
80    pub extern "C" fn systry_get_stdin() -> COption<usize> {
81        STDIO.stdin.clone()
82    }
83}
84
85exported_func! {
86    /// Returns the resource id of the stdout file descriptor
87    ///
88    /// if there is no stdout file descriptor, it will fall back to `dev:/tty`
89    pub extern "C" fn sysget_stdout() -> usize {
90        *STDOUT
91    }
92}
93
94exported_func! {
95    /// Returns the resource id of the stderr file descriptor
96    ///
97    /// if there is no stderr file descriptor, it will fall back to `dev:/tty`
98    pub extern "C" fn sysget_stderr() -> usize {
99        *STDERR
100    }
101}
102
103exported_func! {
104    /// Returns the resource id of the stdin file descriptor
105    ///
106    /// if there is no stdin file descriptor, it will fall back to `dev:/tty`
107    pub extern "C" fn sysget_stdin() -> usize {
108        *STDIN
109    }
110}
111
112pub fn init_meta(abi_structures: AbiStructures) {
113    unsafe { ABI_STRUCTURES.init(abi_structures) };
114}