diff --git a/src/Cargo.lock b/src/Cargo.lock index d7b7bf0e..da8e817c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -245,6 +245,7 @@ dependencies = [ "spin 0.9.4", "uart_16550", "volatile", + "x86", "x86_64", ] @@ -459,6 +460,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags", +] + [[package]] name = "ringbuffer" version = "0.10.0" @@ -706,6 +716,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "x86" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" +dependencies = [ + "bit_field", + "bitflags", + "raw-cpuid", +] + [[package]] name = "x86_64" version = "0.14.10" diff --git a/src/services/libs/jinux-std/src/lib.rs b/src/services/libs/jinux-std/src/lib.rs index e7c0ac6b..84129d2f 100644 --- a/src/services/libs/jinux-std/src/lib.rs +++ b/src/services/libs/jinux-std/src/lib.rs @@ -20,6 +20,7 @@ use crate::{ prelude::*, + thread::{kernel_thread::KernelThreadExt, Thread}, user_apps::{get_all_apps, get_busybox_app, UserApp}, }; use process::Process; @@ -60,34 +61,18 @@ pub fn init_thread() { current_thread!().tid() ); // driver::pci::virtio::block::block_device_test(); - let process = Process::spawn_kernel_process(|| { + let thread = Thread::spawn_kernel_thread(|| { println!("[kernel] Hello world from kernel!"); let current = current_thread!(); - let pid = current.tid(); - debug!("current pid = {}", pid); + let tid = current.tid(); + debug!("current tid = {}", tid); }); + thread.join(); info!( "[jinux-std/lib.rs] spawn kernel thread, tid = {}", - process.pid() + thread.tid() ); - - // FIXME: should be running this apps before we running shell? - println!(""); - println!("[kernel] Running test programs"); - println!(""); - // Run test apps - for app in get_all_apps().unwrap().into_iter() { - let UserApp { - elf_path: app_name, - app_content, - argv, - envp, - } = app; - let app_content = app_content.into_boxed_slice(); - println!("[jinux-std/lib.rs] spwan {:?} process", app_name); - Process::spawn_user_process(app_name.clone(), Box::leak(app_content), argv, Vec::new()); - } - + // Run busybox ash let UserApp { elf_path: app_name, @@ -102,8 +87,8 @@ pub fn init_thread() { loop { // We don't have preemptive scheduler now. - // The long running init process should yield its own execution to allow other tasks to go on. - let _ = wait_child_exit(ProcessFilter::Any, WaitOptions::empty()); + // The long running init thread should yield its own execution to allow other tasks to go on. + Thread::yield_now(); } } @@ -114,6 +99,6 @@ fn read_ramdisk_content() -> &'static [u8] { /// first process never return #[controlled] pub fn run_first_process() -> ! { - Process::spawn_kernel_process(init_thread); + Thread::spawn_kernel_thread(init_thread); unreachable!() } diff --git a/src/services/libs/jinux-std/src/process/clone.rs b/src/services/libs/jinux-std/src/process/clone.rs index 7041a134..57b26819 100644 --- a/src/services/libs/jinux-std/src/process/clone.rs +++ b/src/services/libs/jinux-std/src/process/clone.rs @@ -169,7 +169,7 @@ fn clone_child_thread(parent_context: CpuContext, clone_args: CloneArgs) -> Resu let child_tid = allocate_tid(); // inherit sigmask from current thread let current_thread = current_thread!(); - let current_posix_thread = current_thread.posix_thread(); + let current_posix_thread = current_thread.as_posix_thread().unwrap(); let sig_mask = current_posix_thread.sig_mask().lock().clone(); let is_main_thread = child_tid == current.pid(); let thread_builder = PosixThreadBuilder::new(child_tid, child_user_space) @@ -177,7 +177,7 @@ fn clone_child_thread(parent_context: CpuContext, clone_args: CloneArgs) -> Resu .is_main_thread(is_main_thread); let child_thread = thread_builder.build(); current.threads.lock().push(child_thread.clone()); - let child_posix_thread = child_thread.posix_thread(); + let child_posix_thread = child_thread.as_posix_thread().unwrap(); clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?; clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?; clone_child_settid( @@ -191,6 +191,7 @@ fn clone_child_thread(parent_context: CpuContext, clone_args: CloneArgs) -> Resu fn clone_child_process(parent_context: CpuContext, clone_args: CloneArgs) -> Result> { let current = current!(); + let parent = Arc::downgrade(¤t); let clone_flags = clone_args.clone_flags; // clone vm @@ -222,7 +223,7 @@ fn clone_child_process(parent_context: CpuContext, clone_args: CloneArgs) -> Res // inherit parent's sig mask let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let child_sig_mask = posix_thread.sig_mask().lock().clone(); let child_tid = allocate_tid(); @@ -237,6 +238,7 @@ fn clone_child_process(parent_context: CpuContext, clone_args: CloneArgs) -> Res let child_thread = child_thread_builder.build(); Process::new( child_pid, + parent, vec![child_thread], Some(child_elf_path), child_user_vm, @@ -256,7 +258,7 @@ fn clone_child_process(parent_context: CpuContext, clone_args: CloneArgs) -> Res process_table::add_process(child.clone()); let child_thread = thread_table::tid_to_thread(child_tid).unwrap(); - let child_posix_thread = child_thread.posix_thread(); + let child_posix_thread = child_thread.as_posix_thread().unwrap(); clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?; clone_child_cleartid(child_posix_thread, clone_args.child_tidptr, clone_flags)?; clone_child_settid( diff --git a/src/services/libs/jinux-std/src/process/mod.rs b/src/services/libs/jinux-std/src/process/mod.rs index 2962f3ed..fb502ac4 100644 --- a/src/services/libs/jinux-std/src/process/mod.rs +++ b/src/services/libs/jinux-std/src/process/mod.rs @@ -14,7 +14,6 @@ use crate::fs::file_table::FileTable; use crate::fs::fs_resolver::FsResolver; use crate::prelude::*; use crate::rights::Full; -use crate::thread::kernel_thread::KernelThreadExt; use crate::thread::{thread_table, Thread}; use crate::tty::get_n_tty; use crate::vm::vmar::Vmar; @@ -38,6 +37,8 @@ pub type Pid = i32; pub type Pgid = i32; pub type ExitCode = i32; +const INIT_PROCESS_PID: Pid = 1; + /// Process stands for a set of threads that shares the same userspace. /// Currently, we only support one thread inside a process. pub struct Process { @@ -82,20 +83,17 @@ impl Process { /// returns the current process pub fn current() -> Arc { let current_thread = Thread::current(); - if current_thread.is_posix_thread() { - let posix_thread = current_thread.posix_thread(); + if let Some(posix_thread) = current_thread.as_posix_thread() { posix_thread.process() - } else if current_thread.is_kernel_thread() { - let kernel_thread = current_thread.kernel_thread(); - kernel_thread.process() } else { - panic!("[Internal error]The process is neither kernel process or user process"); + panic!("[Internal error]The current thread does not belong to a process"); } } /// create a new process(not schedule it) pub fn new( pid: Pid, + parent: Weak, threads: Vec>, elf_path: Option, user_vm: Option, @@ -105,12 +103,6 @@ impl Process { fs: Arc>, sig_dispositions: Arc>, ) -> Self { - let parent = if pid == 0 { - Weak::new() - } else { - let current_process = current!(); - Arc::downgrade(¤t_process) - }; let children = BTreeMap::new(); let waiting_children = WaitQueue::new(); let poll_queue = WaitQueue::new(); @@ -161,20 +153,6 @@ impl Process { process } - /// init a kernel process and run the process - pub fn spawn_kernel_process(task_fn: F) -> Arc - where - F: Fn() + Send + Sync + 'static, - { - let process_fn = move || { - task_fn(); - current!().exit_group(0); - }; - let process = Process::create_kernel_process(process_fn); - process.run(); - process - } - fn create_user_process( elf_path: CString, elf_file_content: &'static [u8], @@ -185,7 +163,12 @@ impl Process { let weak_process = weak_process_ref.clone(); let cloned_filename = Some(elf_path.clone()); let root_vmar = Vmar::::new_root().unwrap(); +<<<<<<< HEAD let thread = Thread::new_posix_thread_from_elf( +======= + let fs = FsResolver::new(); + let thread = Thread::new_posix_thread_from_executable( +>>>>>>> 0255134... fix &root_vmar, elf_path, elf_file_content, @@ -194,6 +177,8 @@ impl Process { envp, ); let pid = thread.tid(); + // spawn process will be called in a kernel thread, so the parent process is always none. + let parent = Weak::new(); let user_vm = UserVm::new(); let file_table = FileTable::new_with_stdio(); let fs = FsResolver::new(); @@ -201,6 +186,7 @@ impl Process { let process = Process::new( pid, + parent, vec![thread], cloned_filename, Some(user_vm), @@ -215,44 +201,10 @@ impl Process { // Set process group user_process.create_and_set_process_group(); process_table::add_process(user_process.clone()); - let parent = user_process - .parent() - .expect("[Internel error] User process should always have parent"); - parent.add_child(user_process.clone()); - user_process - } - - fn create_kernel_process(task_fn: F) -> Arc - where - F: Fn() + Send + Sync + 'static, - { - let kernel_process = Arc::new_cyclic(|weak_process_ref| { - let weak_process = weak_process_ref.clone(); - let thread = Thread::new_kernel_thread(task_fn, weak_process_ref.clone()); - let pid = thread.tid(); - let file_table = FileTable::new(); - let fs = FsResolver::new(); - let sig_dispositions = SigDispositions::new(); - // FIXME: kernel process does not need root vmar - let root_vmar = Vmar::::new_root().unwrap(); - Process::new( - pid, - vec![thread], - None, - None, - Arc::new(root_vmar), - Weak::new(), - Arc::new(Mutex::new(file_table)), - Arc::new(RwLock::new(fs)), - Arc::new(Mutex::new(sig_dispositions)), - ) - }); - kernel_process.create_and_set_process_group(); - process_table::add_process(kernel_process.clone()); - if let Some(parent) = kernel_process.parent() { - parent.add_child(kernel_process.clone()); + if let Some(parent) = user_process.parent() { + parent.add_child(user_process.clone()); } - kernel_process + user_process } /// returns the pid of the process @@ -326,10 +278,11 @@ impl Process { } // move children to the init process if !self.is_init_process() { - let init_process = get_init_process(); - for (_, child_process) in self.children.lock().drain_filter(|_, _| true) { - child_process.set_parent(Arc::downgrade(&init_process)); - init_process.add_child(child_process); + if let Some(init_process) = get_init_process() { + for (_, child_process) in self.children.lock().drain_filter(|_, _| true) { + child_process.set_parent(Arc::downgrade(&init_process)); + init_process.add_child(child_process); + } } } @@ -362,11 +315,6 @@ impl Process { &self.threads } - /// yield the current process to allow other processes to run - pub fn yield_now() { - Task::yield_now(); - } - /// returns the user_vm pub fn user_vm(&self) -> Option<&UserVm> { self.user_vm.as_ref() @@ -435,15 +383,6 @@ impl Process { } /// Get the init process -pub fn get_init_process() -> Arc { - let mut current_process = current!(); - while current_process.pid() != 0 { - let process = current_process - .parent - .lock() - .upgrade() - .expect("[Internal Error] init process cannot be None"); - current_process = process; - } - current_process +pub fn get_init_process() -> Option> { + process_table::pid_to_process(INIT_PROCESS_PID) } diff --git a/src/services/libs/jinux-std/src/process/posix_thread/posix_thread_ext.rs b/src/services/libs/jinux-std/src/process/posix_thread/posix_thread_ext.rs index 120cd43a..574d158f 100644 --- a/src/services/libs/jinux-std/src/process/posix_thread/posix_thread_ext.rs +++ b/src/services/libs/jinux-std/src/process/posix_thread/posix_thread_ext.rs @@ -10,9 +10,8 @@ use crate::{ use super::{builder::PosixThreadBuilder, name::ThreadName, PosixThread}; pub trait PosixThreadExt { - fn is_posix_thread(&self) -> bool; - fn posix_thread(&self) -> &PosixThread; - fn new_posix_thread_from_elf( + fn as_posix_thread(&self) -> Option<&PosixThread>; + fn new_posix_thread_from_executable( root_vmar: &Vmar, elf_path: CString, elf_file_content: &'static [u8], @@ -24,7 +23,7 @@ pub trait PosixThreadExt { impl PosixThreadExt for Thread { /// This function should only be called when launch shell() - fn new_posix_thread_from_elf( + fn new_posix_thread_from_executable( root_vmar: &Vmar, elf_path: CString, elf_file_content: &'static [u8], @@ -47,11 +46,7 @@ impl PosixThreadExt for Thread { thread_builder.build() } - fn is_posix_thread(&self) -> bool { - self.data().downcast_ref::().is_some() - } - - fn posix_thread(&self) -> &PosixThread { - self.data().downcast_ref::().unwrap() + fn as_posix_thread(&self) -> Option<&PosixThread> { + self.data().downcast_ref::() } } diff --git a/src/services/libs/jinux-std/src/process/signal/mod.rs b/src/services/libs/jinux-std/src/process/signal/mod.rs index c01c1a49..3f6f4d39 100644 --- a/src/services/libs/jinux-std/src/process/signal/mod.rs +++ b/src/services/libs/jinux-std/src/process/signal/mod.rs @@ -29,7 +29,7 @@ use crate::{ pub fn handle_pending_signal(context: &mut CpuContext) -> Result<()> { let current = current!(); let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let pid = current.pid(); let process_name = current.filename().unwrap(); let sig_mask = posix_thread.sig_mask().lock().clone(); @@ -130,7 +130,7 @@ pub fn handle_user_signal( mask.block(current_mask.as_u64()); } let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); // block signals in sigmask when running signal handler posix_thread.sig_mask().lock().block(mask.as_u64()); diff --git a/src/services/libs/jinux-std/src/syscall/execve.rs b/src/services/libs/jinux-std/src/syscall/execve.rs index 520a5d82..f4898fc1 100644 --- a/src/services/libs/jinux-std/src/syscall/execve.rs +++ b/src/services/libs/jinux-std/src/syscall/execve.rs @@ -27,7 +27,7 @@ pub fn sys_execve( } // FIXME: should we set thread name in execve? let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let mut thread_name = posix_thread.thread_name().lock(); let new_thread_name = ThreadName::new_from_elf_path(&elf_path)?; *thread_name = Some(new_thread_name); diff --git a/src/services/libs/jinux-std/src/syscall/exit.rs b/src/services/libs/jinux-std/src/syscall/exit.rs index edc8a295..1e1df1a9 100644 --- a/src/services/libs/jinux-std/src/syscall/exit.rs +++ b/src/services/libs/jinux-std/src/syscall/exit.rs @@ -11,7 +11,7 @@ pub fn sys_exit(exit_code: i32) -> Result { let current = current!(); let pid = current.pid(); debug!("tid = {}, pid = {}", tid, pid); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); current_thread.exit(); posix_thread.exit(tid, exit_code)?; diff --git a/src/services/libs/jinux-std/src/syscall/prctl.rs b/src/services/libs/jinux-std/src/syscall/prctl.rs index 987430e4..2ac1dae2 100644 --- a/src/services/libs/jinux-std/src/syscall/prctl.rs +++ b/src/services/libs/jinux-std/src/syscall/prctl.rs @@ -12,7 +12,7 @@ pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Res let prctl_cmd = PrctlCmd::from_args(option, arg2, arg3, arg4, arg5)?; debug!("prctl cmd = {:?}", prctl_cmd); let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); match prctl_cmd { PrctlCmd::PR_GET_NAME(write_to_addr) => { let thread_name = posix_thread.thread_name().lock(); diff --git a/src/services/libs/jinux-std/src/syscall/rt_sigprocmask.rs b/src/services/libs/jinux-std/src/syscall/rt_sigprocmask.rs index 1b68c2d2..cab5930f 100644 --- a/src/services/libs/jinux-std/src/syscall/rt_sigprocmask.rs +++ b/src/services/libs/jinux-std/src/syscall/rt_sigprocmask.rs @@ -36,7 +36,7 @@ fn do_rt_sigprocmask( ) -> Result<()> { let current = current!(); let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let root_vmar = current.root_vmar(); let mut sig_mask = posix_thread.sig_mask().lock(); let old_sig_mask_value = sig_mask.as_u64(); diff --git a/src/services/libs/jinux-std/src/syscall/rt_sigreturn.rs b/src/services/libs/jinux-std/src/syscall/rt_sigreturn.rs index eb56e859..b69f08cb 100644 --- a/src/services/libs/jinux-std/src/syscall/rt_sigreturn.rs +++ b/src/services/libs/jinux-std/src/syscall/rt_sigreturn.rs @@ -11,7 +11,7 @@ use super::{SyscallReturn, SYS_RT_SIGRETRUN}; pub fn sys_rt_sigreturn(context: &mut CpuContext) -> Result { log_syscall_entry!(SYS_RT_SIGRETRUN); let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let mut sig_context = posix_thread.sig_context().lock(); if None == *sig_context { return_errno_with_message!(Errno::EINVAL, "sigretrun should not been called"); diff --git a/src/services/libs/jinux-std/src/syscall/sched_yield.rs b/src/services/libs/jinux-std/src/syscall/sched_yield.rs index 9fb15c78..d448b97a 100644 --- a/src/services/libs/jinux-std/src/syscall/sched_yield.rs +++ b/src/services/libs/jinux-std/src/syscall/sched_yield.rs @@ -1,11 +1,12 @@ +use crate::thread::Thread; use crate::{log_syscall_entry, prelude::*}; -use crate::{process::Process, syscall::SYS_SCHED_YIELD}; +use crate::syscall::SYS_SCHED_YIELD; use super::SyscallReturn; pub fn sys_sched_yield() -> Result { log_syscall_entry!(SYS_SCHED_YIELD); - Process::yield_now(); + Thread::yield_now(); Ok(SyscallReturn::Return(0)) } diff --git a/src/services/libs/jinux-std/src/syscall/set_robust_list.rs b/src/services/libs/jinux-std/src/syscall/set_robust_list.rs index 1860d05d..6b303db0 100644 --- a/src/services/libs/jinux-std/src/syscall/set_robust_list.rs +++ b/src/services/libs/jinux-std/src/syscall/set_robust_list.rs @@ -21,7 +21,7 @@ pub fn sys_set_robust_list(robust_list_head_ptr: Vaddr, len: usize) -> Result Result { log_syscall_entry!(SYS_SET_TID_ADDRESS); debug!("tidptr = 0x{:x}", tidptr); let current_thread = current_thread!(); - let posix_thread = current_thread.posix_thread(); + let posix_thread = current_thread.as_posix_thread().unwrap(); let mut clear_child_tid = posix_thread.clear_child_tid().lock(); if *clear_child_tid != 0 { // According to manuals at https://man7.org/linux/man-pages/man2/set_tid_address.2.html diff --git a/src/services/libs/jinux-std/src/syscall/tgkill.rs b/src/services/libs/jinux-std/src/syscall/tgkill.rs index b364ac7b..cf68c0ee 100644 --- a/src/services/libs/jinux-std/src/syscall/tgkill.rs +++ b/src/services/libs/jinux-std/src/syscall/tgkill.rs @@ -18,7 +18,7 @@ pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8) -> Result { info!("tgid = {}, pid = {}, sig_num = {:?}", tgid, tid, sig_num); let target_thread = thread_table::tid_to_thread(tid) .ok_or(Error::with_message(Errno::EINVAL, "Invalid pid"))?; - let posix_thread = target_thread.posix_thread(); + let posix_thread = target_thread.as_posix_thread().unwrap(); let pid = posix_thread.process().pid(); if pid != tgid { return_errno_with_message!( diff --git a/src/services/libs/jinux-std/src/thread/kernel_thread.rs b/src/services/libs/jinux-std/src/thread/kernel_thread.rs index fafcac0e..6272458a 100644 --- a/src/services/libs/jinux-std/src/thread/kernel_thread.rs +++ b/src/services/libs/jinux-std/src/thread/kernel_thread.rs @@ -1,28 +1,32 @@ use jinux_frame::task::Task; -use crate::{prelude::*, process::Process}; +use crate::prelude::*; use super::{allocate_tid, status::ThreadStatus, thread_table, Thread}; -pub struct KernelThread { - process: Weak, -} -impl KernelThread { - pub fn new(process: Weak) -> Self { - Self { process } - } - - pub fn process(&self) -> Arc { - self.process.upgrade().unwrap() - } -} +/// This struct is used to mark a thread is a kernel thread +pub struct KernelThread; pub trait KernelThreadExt { + /// whether the thread is a kernel thread fn is_kernel_thread(&self) -> bool; + /// get the kernel_thread structure fn kernel_thread(&self) -> &KernelThread; - fn new_kernel_thread(task_fn: F, process: Weak) -> Arc + /// create a new kernel thread structure, **NOT** run the thread. + fn new_kernel_thread(task_fn: F) -> Arc where F: Fn() + Send + Sync + 'static; + /// create a new kernel thread structure, and then run the thread. + fn spawn_kernel_thread(task_fn: F) -> Arc + where + F: Fn() + Send + Sync + 'static, + { + let thread = Self::new_kernel_thread(task_fn); + thread.run(); + thread + } + /// join a kernel thread + fn join(&self); } impl KernelThreadExt for Thread { @@ -34,19 +38,38 @@ impl KernelThreadExt for Thread { self.data().downcast_ref::().unwrap() } - fn new_kernel_thread(task_fn: F, process: Weak) -> Arc + fn new_kernel_thread(task_fn: F) -> Arc where F: Fn() + Send + Sync + 'static, { + + let thread_fn = move || { + task_fn(); + let current_thread = current_thread!(); + // ensure the thread is exit + current_thread.exit(); + }; let tid = allocate_tid(); let thread = Arc::new_cyclic(|thread_ref| { let weal_thread = thread_ref.clone(); - let task = Task::new(task_fn, weal_thread, None).unwrap(); + let task = Task::new(thread_fn, weal_thread, None).unwrap(); let status = ThreadStatus::Init; - let kernel_thread = KernelThread::new(process); + let kernel_thread = KernelThread; Thread::new(tid, task, kernel_thread, status) }); thread_table::add_thread(thread.clone()); thread } + + fn join(&self) { + loop { + let status = self.status.lock(); + if status.is_exited() { + return; + } else { + drop(status); + Thread::yield_now(); + } + } + } }