115 lines
2.6 KiB
Rust
115 lines
2.6 KiB
Rust
use core::{
|
|
ffi::{c_char, c_int, c_void, CStr}, mem::MaybeUninit, time::Duration
|
|
};
|
|
|
|
use yggdrasil_rt::{
|
|
process::{ExitCode, Signal}, sync::mutex::Mutex, sys as syscall
|
|
};
|
|
use alloc::vec::Vec;
|
|
|
|
use crate::{
|
|
headers::sys_types::pid_t,
|
|
io::{self, managed::stderr},
|
|
};
|
|
|
|
struct DsoDestructor {
|
|
f: extern "C" fn (*mut c_void),
|
|
arg: *mut c_void,
|
|
}
|
|
|
|
unsafe impl Sync for DsoDestructor {}
|
|
|
|
impl DsoDestructor {
|
|
unsafe fn invoke(self) {
|
|
(self.f)(self.arg)
|
|
}
|
|
}
|
|
|
|
static AT_EXIT: Mutex<Vec<extern "C" fn()>> = Mutex::new(Vec::new());
|
|
// TODO this will be in the linker instead
|
|
static AT_DSO_EXIT: Mutex<Vec<DsoDestructor>> = Mutex::new(Vec::new());
|
|
|
|
pub fn getpid() -> pid_t {
|
|
let pid = unsafe { syscall::get_pid() };
|
|
pid.into_raw().try_into().unwrap()
|
|
}
|
|
|
|
pub fn getpgrp() -> pid_t {
|
|
let pgid = unsafe { syscall::get_process_group_id() };
|
|
pgid.into_raw().try_into().unwrap()
|
|
}
|
|
|
|
pub fn sleep(duration: Duration) -> Result<(), Duration> {
|
|
let mut remaining = MaybeUninit::uninit();
|
|
if unsafe { syscall::nanosleep(&duration, &mut remaining) }.is_ok() {
|
|
Ok(())
|
|
} else {
|
|
Err(unsafe { remaining.assume_init() })
|
|
}
|
|
}
|
|
|
|
pub fn abort() -> ! {
|
|
let pid = unsafe { syscall::get_pid() };
|
|
unsafe { syscall::send_signal(pid, Signal::Aborted).ok() };
|
|
unreachable!()
|
|
}
|
|
|
|
pub fn c_exit_immediately(status: c_int) -> ! {
|
|
let code = ExitCode::Exited(status);
|
|
unsafe { syscall::exit_process(code) };
|
|
}
|
|
|
|
pub fn c_exit(status: c_int) -> ! {
|
|
unsafe {
|
|
pre_exit();
|
|
c_exit_immediately(status)
|
|
}
|
|
}
|
|
|
|
pub fn at_exit(f: extern "C" fn()) {
|
|
AT_EXIT.lock().push(f);
|
|
}
|
|
|
|
pub fn at_dso_exit(f: extern "C" fn(*mut c_void), arg: *mut c_void, _dso_handle: *mut c_void) {
|
|
// TODO no support for dlopen/dlclose, so at_dso_exit == at_exit right now
|
|
AT_DSO_EXIT.lock().push(DsoDestructor {
|
|
f,
|
|
arg
|
|
});
|
|
}
|
|
|
|
unsafe fn call_atexit() {
|
|
for d in AT_DSO_EXIT.lock().drain(..) {
|
|
d.invoke();
|
|
}
|
|
for f in AT_EXIT.lock().drain(..) {
|
|
f();
|
|
}
|
|
}
|
|
|
|
unsafe fn pre_exit() {
|
|
call_atexit();
|
|
io::cleanup();
|
|
}
|
|
|
|
#[no_mangle]
|
|
unsafe extern "C" fn __assert_fail(file: *const c_char, line: c_int, message: *const c_char) -> ! {
|
|
use core::fmt::Write;
|
|
|
|
let err = stderr.as_mut().unwrap();
|
|
let file = match file.is_null() {
|
|
false => CStr::from_ptr(file).to_str().ok(),
|
|
true => None,
|
|
}
|
|
.unwrap_or("???");
|
|
let expr = match message.is_null() {
|
|
false => CStr::from_ptr(message).to_str().ok(),
|
|
true => None,
|
|
}
|
|
.unwrap_or("???");
|
|
|
|
writeln!(err, "Assertion failed: '{}' at {}:{}", expr, file, line).ok();
|
|
|
|
abort()
|
|
}
|