mod futex;
mod ops;
mod resources;
mod signal;
mod stat;
mod timer;
mod user;
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
use core::{
cell::RefCell,
ops::Deref,
sync::atomic::{AtomicBool, AtomicI32, AtomicU32, AtomicUsize, Ordering},
};
use axpoll::PollSet;
use axsync::{Mutex, spin::SpinNoIrq};
use axtask::{TaskExt, TaskInner};
use extern_trait::extern_trait;
use scope_local::{ActiveScope, Scope};
use spin::RwLock;
use starry_process::Process;
use starry_signal::{
Signo,
api::{ProcessSignalManager, SignalActions, ThreadSignalManager},
};
pub use self::{futex::*, ops::*, resources::*, signal::*, stat::*, timer::*, user::*};
use crate::mm::AddrSpace;
#[repr(transparent)]
pub struct AssumeSync<T>(pub T);
unsafe impl<T> Sync for AssumeSync<T> {}
impl<T> Deref for AssumeSync<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub struct Thread {
pub proc_data: Arc<ProcessData>,
clear_child_tid: AtomicUsize,
robust_list_head: AtomicUsize,
pub signal: Arc<ThreadSignalManager>,
pub time: AssumeSync<RefCell<TimeManager>>,
oom_score_adj: AtomicI32,
pub exit: Arc<AtomicBool>,
accessing_user_memory: AtomicBool,
pub exit_event: Arc<PollSet>,
}
impl Thread {
pub fn new(tid: u32, proc_data: Arc<ProcessData>) -> Box<Self> {
Box::new(Thread {
signal: ThreadSignalManager::new(tid, proc_data.signal.clone()),
proc_data,
clear_child_tid: AtomicUsize::new(0),
robust_list_head: AtomicUsize::new(0),
time: AssumeSync(RefCell::new(TimeManager::new())),
exit: Arc::new(AtomicBool::new(false)),
oom_score_adj: AtomicI32::new(200),
accessing_user_memory: AtomicBool::new(false),
exit_event: Arc::default(),
})
}
pub fn clear_child_tid(&self) -> usize {
self.clear_child_tid.load(Ordering::Relaxed)
}
pub fn set_clear_child_tid(&self, clear_child_tid: usize) {
self.clear_child_tid
.store(clear_child_tid, Ordering::Relaxed);
}
pub fn robust_list_head(&self) -> usize {
self.robust_list_head.load(Ordering::SeqCst)
}
pub fn set_robust_list_head(&self, robust_list_head: usize) {
self.robust_list_head
.store(robust_list_head, Ordering::SeqCst);
}
pub fn oom_score_adj(&self) -> i32 {
self.oom_score_adj.load(Ordering::SeqCst)
}
pub fn set_oom_score_adj(&self, value: i32) {
self.oom_score_adj.store(value, Ordering::SeqCst);
}
pub fn pending_exit(&self) -> bool {
self.exit.load(Ordering::Acquire)
}
pub fn set_exit(&self) {
self.exit.store(true, Ordering::Release);
}
pub fn is_accessing_user_memory(&self) -> bool {
self.accessing_user_memory.load(Ordering::Acquire)
}
pub fn set_accessing_user_memory(&self, accessing: bool) {
self.accessing_user_memory
.store(accessing, Ordering::Release);
}
}
#[extern_trait]
impl TaskExt for Box<Thread> {
fn on_enter(&self) {
let scope = self.proc_data.scope.read();
unsafe { ActiveScope::set(&scope) };
core::mem::forget(scope);
}
fn on_leave(&self) {
ActiveScope::set_global();
unsafe { self.proc_data.scope.force_read_decrement() };
}
}
pub trait AsThread {
fn try_as_thread(&self) -> Option<&Thread>;
fn as_thread(&self) -> &Thread {
self.try_as_thread().expect("kernel task")
}
}
impl AsThread for TaskInner {
fn try_as_thread(&self) -> Option<&Thread> {
self.task_ext()
.map(|ext| ext.downcast_ref::<Box<Thread>>().as_ref())
}
}
pub struct ProcessData {
pub proc: Arc<Process>,
pub exe_path: RwLock<String>,
pub cmdline: RwLock<Arc<Vec<String>>>,
pub aspace: Arc<Mutex<AddrSpace>>,
pub scope: RwLock<Scope>,
heap_top: AtomicUsize,
pub rlim: RwLock<Rlimits>,
pub child_exit_event: Arc<PollSet>,
pub exit_event: Arc<PollSet>,
pub exit_signal: Option<Signo>,
pub signal: Arc<ProcessSignalManager>,
futex_table: Arc<FutexTable>,
umask: AtomicU32,
}
impl ProcessData {
pub fn new(
proc: Arc<Process>,
exe_path: String,
cmdline: Arc<Vec<String>>,
aspace: Arc<Mutex<AddrSpace>>,
signal_actions: Arc<SpinNoIrq<SignalActions>>,
exit_signal: Option<Signo>,
) -> Arc<Self> {
Arc::new(Self {
proc,
exe_path: RwLock::new(exe_path),
cmdline: RwLock::new(cmdline),
aspace,
scope: RwLock::new(Scope::new()),
heap_top: AtomicUsize::new(crate::config::USER_HEAP_BASE),
rlim: RwLock::default(),
child_exit_event: Arc::default(),
exit_event: Arc::default(),
exit_signal,
signal: Arc::new(ProcessSignalManager::new(
signal_actions,
crate::config::SIGNAL_TRAMPOLINE,
)),
futex_table: Arc::new(FutexTable::new()),
umask: AtomicU32::new(0o022),
})
}
pub fn get_heap_top(&self) -> usize {
self.heap_top.load(Ordering::Acquire)
}
pub fn set_heap_top(&self, top: usize) {
self.heap_top.store(top, Ordering::Release)
}
pub fn is_clone_child(&self) -> bool {
self.exit_signal != Some(Signo::SIGCHLD)
}
pub fn umask(&self) -> u32 {
self.umask.load(Ordering::SeqCst)
}
pub fn set_umask(&self, umask: u32) {
self.umask.store(umask, Ordering::SeqCst);
}
pub fn replace_umask(&self, umask: u32) -> u32 {
self.umask.swap(umask, Ordering::SeqCst)
}
}