mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-23 03:53:26 +00:00
添加thread和futex机制 (#411)
* 初步实现clone系统调用 * 实现了线程,初步实现futex机制,添加了几个小的系统调用 * 更改pcb引用计数问题 * 解决死锁bug --------- Co-authored-by: LoGin <longjin@DragonOS.org>
This commit is contained in:
@ -36,16 +36,25 @@ pub extern "C" fn rs_current_pcb_pid() -> u32 {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_current_pcb_preempt_count() -> u32 {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return 0;
|
||||
}
|
||||
return ProcessManager::current_pcb().preempt_count() as u32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_current_pcb_flags() -> u32 {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return 0;
|
||||
}
|
||||
return ProcessManager::current_pcb().flags().bits() as u32;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_current_pcb_thread_rbp() -> u64 {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return 0;
|
||||
}
|
||||
return ProcessManager::current_pcb().arch_info_irqsave().rbp() as u64;
|
||||
}
|
||||
|
||||
@ -61,5 +70,8 @@ pub extern "C" fn rs_preempt_enable() {
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_process_do_exit(exit_code: usize) -> usize {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return 0;
|
||||
}
|
||||
ProcessManager::exit(exit_code);
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
arch::interrupt::TrapFrame, filesystem::procfs::procfs_register_pid,
|
||||
ipc::signal::flush_signal_handlers, libs::rwlock::RwLock, process::ProcessFlags,
|
||||
syscall::SystemError,
|
||||
arch::interrupt::TrapFrame,
|
||||
filesystem::procfs::procfs_register_pid,
|
||||
ipc::signal::flush_signal_handlers,
|
||||
libs::rwlock::RwLock,
|
||||
mm::VirtAddr,
|
||||
process::ProcessFlags,
|
||||
syscall::{user_access::UserBufferWriter, SystemError},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -13,21 +17,116 @@ use super::{
|
||||
|
||||
bitflags! {
|
||||
/// 进程克隆标志
|
||||
pub struct CloneFlags: u32 {
|
||||
/// 在进程间共享文件系统信息
|
||||
const CLONE_FS = (1 << 0);
|
||||
/// 克隆时,与父进程共享信号结构体
|
||||
const CLONE_SIGNAL = (1 << 1);
|
||||
/// 克隆时,与父进程共享信号处理结构体
|
||||
const CLONE_SIGHAND = (1 << 2);
|
||||
/// 克隆时,将原本被设置为SIG_IGNORE的信号,设置回SIG_DEFAULT
|
||||
const CLONE_CLEAR_SIGHAND = (1 << 3);
|
||||
pub struct CloneFlags: u64 {
|
||||
/// 在进程间共享虚拟内存空间
|
||||
const CLONE_VM = (1 << 4);
|
||||
/// 拷贝线程
|
||||
const CLONE_THREAD = (1 << 5);
|
||||
const CLONE_VM = 0x00000100;
|
||||
/// 在进程间共享文件系统信息
|
||||
const CLONE_FS = 0x00000200;
|
||||
/// 共享打开的文件
|
||||
const CLONE_FILES = (1 << 6);
|
||||
const CLONE_FILES = 0x00000400;
|
||||
/// 克隆时,与父进程共享信号处理结构体
|
||||
const CLONE_SIGHAND = 0x00000800;
|
||||
/// 返回进程的文件描述符
|
||||
const CLONE_PIDFD = 0x00001000;
|
||||
/// 使克隆对象成为父进程的跟踪对象
|
||||
const CLONE_PTRACE = 0x00002000;
|
||||
/// 在执行 exec() 或 _exit() 之前挂起父进程的执行
|
||||
const CLONE_VFORK = 0x00004000;
|
||||
/// 使克隆对象的父进程为调用进程的父进程
|
||||
const CLONE_PARENT = 0x00008000;
|
||||
/// 拷贝线程
|
||||
const CLONE_THREAD = 0x00010000;
|
||||
/// 创建一个新的命名空间,其中包含独立的文件系统挂载点层次结构。
|
||||
const CLONE_NEWNS = 0x00020000;
|
||||
/// 与父进程共享 System V 信号量。
|
||||
const CLONE_SYSVSEM = 0x00040000;
|
||||
/// 设置其线程本地存储
|
||||
const CLONE_SETTLS = 0x00080000;
|
||||
/// 设置partent_tid地址为子进程线程 ID
|
||||
const CLONE_PARENT_SETTID = 0x00100000;
|
||||
/// 在子进程中设置一个清除线程 ID 的用户空间地址
|
||||
const CLONE_CHILD_CLEARTID = 0x00200000;
|
||||
/// 创建一个新线程,将其设置为分离状态
|
||||
const CLONE_DETACHED = 0x00400000;
|
||||
/// 使其在创建者进程或线程视角下成为无法跟踪的。
|
||||
const CLONE_UNTRACED = 0x00800000;
|
||||
/// 设置其子进程线程 ID
|
||||
const CLONE_CHILD_SETTID = 0x01000000;
|
||||
/// 将其放置在一个新的 cgroup 命名空间中
|
||||
const CLONE_NEWCGROUP = 0x02000000;
|
||||
/// 将其放置在一个新的 UTS 命名空间中
|
||||
const CLONE_NEWUTS = 0x04000000;
|
||||
/// 将其放置在一个新的 IPC 命名空间中
|
||||
const CLONE_NEWIPC = 0x08000000;
|
||||
/// 将其放置在一个新的用户命名空间中
|
||||
const CLONE_NEWUSER = 0x10000000;
|
||||
/// 将其放置在一个新的 PID 命名空间中
|
||||
const CLONE_NEWPID = 0x20000000;
|
||||
/// 将其放置在一个新的网络命名空间中
|
||||
const CLONE_NEWNET = 0x40000000;
|
||||
/// 在新的 I/O 上下文中运行它
|
||||
const CLONE_IO = 0x80000000;
|
||||
/// 克隆时,与父进程共享信号结构体
|
||||
const CLONE_SIGNAL = 0x00010000 | 0x00000800;
|
||||
/// 克隆时,将原本被设置为SIG_IGNORE的信号,设置回SIG_DEFAULT
|
||||
const CLONE_CLEAR_SIGHAND = 0x100000000;
|
||||
}
|
||||
}
|
||||
|
||||
/// ## clone与clone3系统调用的参数载体
|
||||
///
|
||||
/// 因为这两个系统调用的参数很多,所以有这样一个载体更灵活
|
||||
///
|
||||
/// 仅仅作为参数传递
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct KernelCloneArgs {
|
||||
pub flags: CloneFlags,
|
||||
|
||||
// 下列属性均来自用户空间
|
||||
pub pidfd: VirtAddr,
|
||||
pub child_tid: VirtAddr,
|
||||
pub parent_tid: VirtAddr,
|
||||
pub set_tid: VirtAddr,
|
||||
|
||||
pub exit_signal: i32,
|
||||
|
||||
pub stack: usize,
|
||||
// clone3用到
|
||||
pub stack_size: usize,
|
||||
pub tls: usize,
|
||||
|
||||
pub set_tid_size: usize,
|
||||
pub cgroup: i32,
|
||||
|
||||
pub io_thread: bool,
|
||||
pub kthread: bool,
|
||||
pub idle: bool,
|
||||
pub func: VirtAddr,
|
||||
pub fn_arg: VirtAddr,
|
||||
// cgrp 和 cset?
|
||||
}
|
||||
|
||||
impl KernelCloneArgs {
|
||||
pub fn new() -> Self {
|
||||
let null_addr = VirtAddr::new(0);
|
||||
Self {
|
||||
flags: unsafe { CloneFlags::from_bits_unchecked(0) },
|
||||
pidfd: null_addr,
|
||||
child_tid: null_addr,
|
||||
parent_tid: null_addr,
|
||||
set_tid: null_addr,
|
||||
exit_signal: 0,
|
||||
stack: 0,
|
||||
stack_size: 0,
|
||||
tls: 0,
|
||||
set_tid_size: 0,
|
||||
cgroup: 0,
|
||||
io_thread: false,
|
||||
kthread: false,
|
||||
idle: false,
|
||||
func: null_addr,
|
||||
fn_arg: null_addr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,53 +155,9 @@ impl ProcessManager {
|
||||
let name = current_pcb.basic().name().to_string();
|
||||
let pcb = ProcessControlBlock::new(name, new_kstack);
|
||||
|
||||
// 克隆架构相关信息
|
||||
*pcb.arch_info() = current_pcb.arch_info_irqsave().clone();
|
||||
|
||||
// 为内核线程设置worker private字段。(也许由内核线程机制去做会更好?)
|
||||
if current_pcb.flags().contains(ProcessFlags::KTHREAD) {
|
||||
*pcb.worker_private() = Some(WorkerPrivate::KernelThread(KernelThreadPcbPrivate::new()))
|
||||
}
|
||||
|
||||
// 拷贝标志位
|
||||
ProcessManager::copy_flags(&clone_flags, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy flags from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝用户地址空间
|
||||
ProcessManager::copy_mm(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy mm from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝文件描述符表
|
||||
ProcessManager::copy_files(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy files from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
//拷贝信号相关数据
|
||||
ProcessManager::copy_sighand(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy sighands from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝线程
|
||||
ProcessManager::copy_thread(&clone_flags, ¤t_pcb, &pcb, ¤t_trapframe).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy thread from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
let mut args = KernelCloneArgs::new();
|
||||
args.flags = clone_flags;
|
||||
Self::copy_process(¤t_pcb, &pcb, args, current_trapframe)?;
|
||||
|
||||
ProcessManager::add_pcb(pcb.clone());
|
||||
|
||||
@ -168,7 +223,6 @@ impl ProcessManager {
|
||||
unsafe { new_pcb.basic_mut().set_user_vm(Some(old_address_space)) };
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let new_address_space = old_address_space.write().try_clone().unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"copy_mm: Failed to clone address space of current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
@ -215,4 +269,139 @@ impl ProcessManager {
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 拷贝进程信息
|
||||
///
|
||||
/// ## panic:
|
||||
/// 某一步拷贝失败时会引发panic
|
||||
/// 例如:copy_mm等失败时会触发panic
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - clone_flags 标志位
|
||||
/// - des_pcb 目标pcb
|
||||
/// - src_pcb 拷贝源pcb
|
||||
///
|
||||
/// ## return
|
||||
/// - 发生错误时返回Err(SystemError)
|
||||
pub fn copy_process(
|
||||
current_pcb: &Arc<ProcessControlBlock>,
|
||||
pcb: &Arc<ProcessControlBlock>,
|
||||
clone_args: KernelCloneArgs,
|
||||
current_trapframe: &mut TrapFrame,
|
||||
) -> Result<(), SystemError> {
|
||||
let clone_flags = clone_args.flags;
|
||||
// 不允许与不同namespace的进程共享根目录
|
||||
if (clone_flags == (CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_FS))
|
||||
|| clone_flags == (CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_FS)
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 线程组必须共享信号,分离线程只能在线程组内启动。
|
||||
if clone_flags.contains(CloneFlags::CLONE_THREAD)
|
||||
&& !clone_flags.contains(CloneFlags::CLONE_SIGHAND)
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 共享信号处理器意味着共享vm。
|
||||
// 线程组也意味着共享vm。阻止这种情况可以简化其他代码。
|
||||
if clone_flags.contains(CloneFlags::CLONE_SIGHAND)
|
||||
&& !clone_flags.contains(CloneFlags::CLONE_VM)
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// TODO: 处理CLONE_PARENT 与 SIGNAL_UNKILLABLE的情况
|
||||
|
||||
// 如果新进程使用不同的 pid 或 namespace,
|
||||
// 则不允许它与分叉任务共享线程组。
|
||||
if clone_flags.contains(CloneFlags::CLONE_THREAD) {
|
||||
if clone_flags.contains(CloneFlags::CLONE_NEWUSER | CloneFlags::CLONE_NEWPID) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
// TODO: 判断新进程与当前进程namespace是否相同,不同则返回错误
|
||||
}
|
||||
|
||||
// 如果新进程将处于不同的time namespace,
|
||||
// 则不能让它共享vm或线程组。
|
||||
if clone_flags.contains(CloneFlags::CLONE_THREAD | CloneFlags::CLONE_VM) {
|
||||
// TODO: 判断time namespace,不同则返回错误
|
||||
}
|
||||
|
||||
if clone_flags.contains(CloneFlags::CLONE_PIDFD)
|
||||
&& clone_flags.contains(CloneFlags::CLONE_DETACHED | CloneFlags::CLONE_THREAD)
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// TODO: 克隆前应该锁信号处理,等待克隆完成后再处理
|
||||
|
||||
// 克隆架构相关
|
||||
*pcb.arch_info() = current_pcb.arch_info_irqsave().clone();
|
||||
|
||||
// 为内核线程设置WorkerPrivate
|
||||
if current_pcb.flags().contains(ProcessFlags::KTHREAD) {
|
||||
*pcb.worker_private() =
|
||||
Some(WorkerPrivate::KernelThread(KernelThreadPcbPrivate::new()));
|
||||
}
|
||||
|
||||
// 设置clear_child_tid,在线程结束时将其置0以通知父进程
|
||||
if clone_flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) {
|
||||
pcb.thread.write().clear_child_tid = Some(clone_args.child_tid);
|
||||
}
|
||||
|
||||
// 设置child_tid,意味着子线程能够知道自己的id
|
||||
if clone_flags.contains(CloneFlags::CLONE_CHILD_SETTID) {
|
||||
pcb.thread.write().set_child_tid = Some(clone_args.child_tid);
|
||||
}
|
||||
|
||||
// 将子进程/线程的id存储在用户态传进的地址中
|
||||
if clone_flags.contains(CloneFlags::CLONE_PARENT_SETTID) {
|
||||
let mut writer = UserBufferWriter::new(
|
||||
clone_args.parent_tid.data() as *mut i32,
|
||||
core::mem::size_of::<i32>(),
|
||||
true,
|
||||
)?;
|
||||
|
||||
writer.copy_one_to_user(&(pcb.pid().0 as i32), 0)?;
|
||||
}
|
||||
|
||||
// 拷贝标志位
|
||||
Self::copy_flags(&clone_flags, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy flags from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝用户地址空间
|
||||
Self::copy_mm(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy mm from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝文件描述符表
|
||||
Self::copy_files(&clone_flags, ¤t_pcb, &pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy files from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// todo: 拷贝信号相关数据
|
||||
|
||||
// 拷贝线程
|
||||
Self::copy_thread(¤t_pcb, &pcb, clone_args,¤t_trapframe).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to copy thread from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -282,9 +282,11 @@ impl KernelThreadMechanism {
|
||||
// 初始化kthreadd
|
||||
let closure = KernelThreadClosure::EmptyClosure((Box::new(Self::kthread_daemon), ()));
|
||||
let info = KernelThreadCreateInfo::new(closure, "kthreadd".to_string());
|
||||
let kthreadd_pid: Pid =
|
||||
Self::__inner_create(&info, CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL)
|
||||
.expect("Failed to create kthread daemon");
|
||||
let kthreadd_pid: Pid = Self::__inner_create(
|
||||
&info,
|
||||
CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
|
||||
)
|
||||
.expect("Failed to create kthread daemon");
|
||||
|
||||
let pcb = ProcessManager::find(kthreadd_pid).unwrap();
|
||||
ProcessManager::wakeup(&pcb).expect("Failed to wakeup kthread daemon");
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::{
|
||||
hash::{Hash, Hasher},
|
||||
hint::spin_loop,
|
||||
intrinsics::{likely, unlikely},
|
||||
mem::ManuallyDrop,
|
||||
sync::atomic::{compiler_fence, AtomicBool, AtomicI32, AtomicIsize, AtomicUsize, Ordering},
|
||||
@ -29,6 +30,10 @@ use crate::{
|
||||
libs::{
|
||||
align::AlignedBox,
|
||||
casting::DowncastArc,
|
||||
futex::{
|
||||
constant::{FutexFlag, FUTEX_BITSET_MATCH_ANY},
|
||||
futex::Futex,
|
||||
},
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
wait_queue::WaitQueue,
|
||||
@ -36,11 +41,12 @@ use crate::{
|
||||
mm::{percpu::PerCpuVar, set_INITIAL_PROCESS_ADDRESS_SPACE, ucontext::AddressSpace, VirtAddr},
|
||||
net::socket::SocketInode,
|
||||
sched::{
|
||||
completion::Completion,
|
||||
core::{sched_enqueue, CPU_EXECUTING},
|
||||
SchedPolicy, SchedPriority,
|
||||
},
|
||||
smp::kick_cpu,
|
||||
syscall::{Syscall, SystemError},
|
||||
syscall::{user_access::clear_user, Syscall, SystemError},
|
||||
};
|
||||
|
||||
use self::kthread::WorkerPrivate;
|
||||
@ -116,6 +122,12 @@ impl ProcessManager {
|
||||
|
||||
/// 获取当前进程的pcb
|
||||
pub fn current_pcb() -> Arc<ProcessControlBlock> {
|
||||
if unlikely(unsafe { !__PROCESS_MANAGEMENT_INIT_DONE }) {
|
||||
kerror!("unsafe__PROCESS_MANAGEMENT_INIT_DONE == false");
|
||||
loop {
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
return ProcessControlBlock::arch_current_pcb();
|
||||
}
|
||||
|
||||
@ -252,7 +264,7 @@ impl ProcessManager {
|
||||
assert_eq!(
|
||||
CurrentIrqArch::is_irq_enabled(),
|
||||
false,
|
||||
"interrupt must be disabled before enter ProcessManager::mark_sleep()"
|
||||
"interrupt must be disabled before enter ProcessManager::mark_stop()"
|
||||
);
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
@ -306,9 +318,31 @@ impl ProcessManager {
|
||||
.write()
|
||||
.set_state(ProcessState::Exited(exit_code));
|
||||
pcb.wait_queue.wakeup(Some(ProcessState::Blocked(true)));
|
||||
|
||||
// 进行进程退出后的工作
|
||||
let thread = pcb.thread.write();
|
||||
if let Some(addr) = thread.set_child_tid {
|
||||
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
|
||||
}
|
||||
|
||||
if let Some(addr) = thread.clear_child_tid {
|
||||
if Arc::strong_count(&pcb.basic().user_vm().expect("User VM Not found")) > 1 {
|
||||
let _ =
|
||||
Futex::futex_wake(addr, FutexFlag::FLAGS_MATCH_NONE, 1, FUTEX_BITSET_MATCH_ANY);
|
||||
}
|
||||
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
|
||||
}
|
||||
|
||||
// 如果是vfork出来的进程,则需要处理completion
|
||||
if thread.vfork_done.is_some() {
|
||||
thread.vfork_done.as_ref().unwrap().complete_all();
|
||||
}
|
||||
drop(thread);
|
||||
unsafe { pcb.basic_mut().set_user_vm(None) };
|
||||
drop(pcb);
|
||||
ProcessManager::exit_notify();
|
||||
drop(irq_guard);
|
||||
|
||||
sched();
|
||||
loop {}
|
||||
}
|
||||
@ -316,15 +350,21 @@ impl ProcessManager {
|
||||
pub unsafe fn release(pid: Pid) {
|
||||
let pcb = ProcessManager::find(pid);
|
||||
if !pcb.is_none() {
|
||||
let pcb = pcb.unwrap();
|
||||
// let pcb = pcb.unwrap();
|
||||
// 判断该pcb是否在全局没有任何引用
|
||||
if Arc::strong_count(&pcb) <= 1 {
|
||||
drop(pcb);
|
||||
ALL_PROCESS.lock().as_mut().unwrap().remove(&pid);
|
||||
} else {
|
||||
// 如果不为1就panic
|
||||
panic!("pcb is still referenced");
|
||||
}
|
||||
// TODO: 当前,pcb的Arc指针存在泄露问题,引用计数不正确,打算在接下来实现debug专用的Arc,方便调试,然后解决这个bug。
|
||||
// 因此目前暂时注释掉,使得能跑
|
||||
// if Arc::strong_count(&pcb) <= 2 {
|
||||
// drop(pcb);
|
||||
// ALL_PROCESS.lock().as_mut().unwrap().remove(&pid);
|
||||
// } else {
|
||||
// // 如果不为1就panic
|
||||
// let msg = format!("pcb '{:?}' is still referenced, strong count={}",pcb.pid(), Arc::strong_count(&pcb));
|
||||
// kerror!("{}", msg);
|
||||
// panic!()
|
||||
// }
|
||||
|
||||
ALL_PROCESS.lock().as_mut().unwrap().remove(&pid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,10 +522,13 @@ pub struct ProcessControlBlock {
|
||||
parent_pcb: RwLock<Weak<ProcessControlBlock>>,
|
||||
|
||||
/// 子进程链表
|
||||
children: RwLock<HashMap<Pid, Arc<ProcessControlBlock>>>,
|
||||
children: RwLock<Vec<Pid>>,
|
||||
|
||||
/// 等待队列
|
||||
wait_queue: WaitQueue,
|
||||
|
||||
/// 线程信息
|
||||
thread: RwLock<ThreadInfo>,
|
||||
}
|
||||
|
||||
impl ProcessControlBlock {
|
||||
@ -545,20 +588,26 @@ impl ProcessControlBlock {
|
||||
sig_info: RwLock::new(ProcessSignalInfo::default()),
|
||||
sig_struct: SpinLock::new(SignalStruct::default()),
|
||||
parent_pcb: RwLock::new(ppcb),
|
||||
children: RwLock::new(HashMap::new()),
|
||||
children: RwLock::new(Vec::new()),
|
||||
wait_queue: WaitQueue::INIT,
|
||||
thread: RwLock::new(ThreadInfo::new()),
|
||||
};
|
||||
|
||||
let pcb = Arc::new(pcb);
|
||||
|
||||
// 设置进程的arc指针到内核栈的最低地址处
|
||||
unsafe { pcb.kernel_stack.write().set_pcb(Arc::clone(&pcb)).unwrap() };
|
||||
unsafe {
|
||||
pcb.kernel_stack
|
||||
.write()
|
||||
.set_pcb(Arc::downgrade(&pcb))
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
// 将当前pcb加入父进程的子进程哈希表中
|
||||
if pcb.pid() > Pid(1) {
|
||||
if let Some(ppcb_arc) = pcb.parent_pcb.read().upgrade() {
|
||||
let mut children = ppcb_arc.children.write();
|
||||
children.insert(pcb.pid(), pcb.clone());
|
||||
children.push(pcb.pid());
|
||||
} else {
|
||||
panic!("parent pcb is None");
|
||||
}
|
||||
@ -700,11 +749,11 @@ impl ProcessControlBlock {
|
||||
unsafe fn adopt_childen(&self) -> Result<(), SystemError> {
|
||||
match ProcessManager::find(Pid(1)) {
|
||||
Some(init_pcb) => {
|
||||
let mut childen_guard = self.children.write();
|
||||
let childen_guard = self.children.write();
|
||||
let mut init_childen_guard = init_pcb.children.write();
|
||||
|
||||
childen_guard.drain().for_each(|(pid, child)| {
|
||||
init_childen_guard.insert(pid, child);
|
||||
childen_guard.iter().for_each(|pid| {
|
||||
init_childen_guard.push(*pid);
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
@ -747,12 +796,31 @@ impl Drop for ProcessControlBlock {
|
||||
.unwrap_or_else(|e| panic!("procfs_unregister_pid failed: error: {e:?}"));
|
||||
|
||||
if let Some(ppcb) = self.parent_pcb.read().upgrade() {
|
||||
ppcb.children.write().remove(&self.pid());
|
||||
ppcb.children.write().drain_filter(|pid| *pid == self.pid());
|
||||
}
|
||||
|
||||
unsafe { ProcessManager::release(self.pid()) };
|
||||
}
|
||||
}
|
||||
|
||||
/// 线程信息
|
||||
#[derive(Debug)]
|
||||
pub struct ThreadInfo {
|
||||
// 来自用户空间记录用户线程id的地址,在该线程结束时将该地址置0以通知父进程
|
||||
clear_child_tid: Option<VirtAddr>,
|
||||
set_child_tid: Option<VirtAddr>,
|
||||
|
||||
vfork_done: Option<Arc<Completion>>,
|
||||
}
|
||||
|
||||
impl ThreadInfo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
clear_child_tid: None,
|
||||
set_child_tid: None,
|
||||
vfork_done: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 进程的基本信息
|
||||
///
|
||||
/// 这个结构体保存进程的基本信息,主要是那些不会随着进程的运行而经常改变的信息。
|
||||
@ -994,9 +1062,9 @@ impl KernelStack {
|
||||
return VirtAddr::new(self.stack.as_ref().unwrap().as_ptr() as usize + Self::SIZE);
|
||||
}
|
||||
|
||||
pub unsafe fn set_pcb(&mut self, pcb: Arc<ProcessControlBlock>) -> Result<(), SystemError> {
|
||||
// 将一个Arc<ProcessControlBlock>放到内核栈的最低地址处
|
||||
let p: *const ProcessControlBlock = Arc::into_raw(pcb);
|
||||
pub unsafe fn set_pcb(&mut self, pcb: Weak<ProcessControlBlock>) -> Result<(), SystemError> {
|
||||
// 将一个Weak<ProcessControlBlock>放到内核栈的最低地址处
|
||||
let p: *const ProcessControlBlock = Weak::into_raw(pcb);
|
||||
let stack_bottom_ptr = self.start_address().data() as *mut *const ProcessControlBlock;
|
||||
|
||||
// 如果内核栈的最低地址处已经有了一个pcb,那么,这里就不再设置,直接返回错误
|
||||
@ -1021,10 +1089,10 @@ impl KernelStack {
|
||||
}
|
||||
|
||||
// 为了防止内核栈的pcb指针被释放,这里需要将其包装一下,使得Arc的drop不会被调用
|
||||
let arc_wrapper: ManuallyDrop<Arc<ProcessControlBlock>> =
|
||||
ManuallyDrop::new(Arc::from_raw(p));
|
||||
let weak_wrapper: ManuallyDrop<Weak<ProcessControlBlock>> =
|
||||
ManuallyDrop::new(Weak::from_raw(p));
|
||||
|
||||
let new_arc: Arc<ProcessControlBlock> = Arc::clone(&arc_wrapper);
|
||||
let new_arc: Arc<ProcessControlBlock> = weak_wrapper.upgrade()?;
|
||||
return Some(new_arc);
|
||||
}
|
||||
}
|
||||
@ -1032,8 +1100,8 @@ impl KernelStack {
|
||||
impl Drop for KernelStack {
|
||||
fn drop(&mut self) {
|
||||
if !self.stack.is_none() {
|
||||
let pcb_ptr: Arc<ProcessControlBlock> = unsafe {
|
||||
Arc::from_raw(self.stack.as_ref().unwrap().as_ptr() as *const ProcessControlBlock)
|
||||
let pcb_ptr: Weak<ProcessControlBlock> = unsafe {
|
||||
Weak::from_raw(self.stack.as_ref().unwrap().as_ptr() as *const ProcessControlBlock)
|
||||
};
|
||||
drop(pcb_ptr);
|
||||
}
|
||||
|
@ -1,13 +1,24 @@
|
||||
use core::ffi::c_void;
|
||||
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use super::{abi::WaitOption, fork::CloneFlags, Pid, ProcessManager, ProcessState};
|
||||
use super::{
|
||||
abi::WaitOption,
|
||||
fork::{CloneFlags, KernelCloneArgs},
|
||||
KernelStack, Pid, ProcessManager, ProcessState,
|
||||
};
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, sched::sched, CurrentIrqArch},
|
||||
exception::InterruptArch,
|
||||
filesystem::vfs::MAX_PATHLEN,
|
||||
filesystem::{procfs::procfs_register_pid, vfs::MAX_PATHLEN},
|
||||
include::bindings::bindings::verify_area,
|
||||
mm::VirtAddr,
|
||||
process::ProcessControlBlock,
|
||||
sched::completion::Completion,
|
||||
syscall::{
|
||||
user_access::{
|
||||
check_and_clone_cstr, check_and_clone_cstr_array, UserBufferReader, UserBufferWriter,
|
||||
@ -42,6 +53,11 @@ impl Syscall {
|
||||
// argv,
|
||||
// envp
|
||||
// );
|
||||
// kdebug!(
|
||||
// "before execve: strong count: {}",
|
||||
// Arc::strong_count(&ProcessManager::current_pcb())
|
||||
// );
|
||||
|
||||
if path.is_null() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
@ -66,6 +82,10 @@ impl Syscall {
|
||||
// 关闭设置了O_CLOEXEC的文件描述符
|
||||
let fd_table = ProcessManager::current_pcb().fd_table();
|
||||
fd_table.write().close_on_exec();
|
||||
// kdebug!(
|
||||
// "after execve: strong count: {}",
|
||||
// Arc::strong_count(&ProcessManager::current_pcb())
|
||||
// );
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
@ -95,12 +115,13 @@ impl Syscall {
|
||||
|
||||
if pid > 0 {
|
||||
let pid = Pid(pid as usize);
|
||||
let child_pcb = rd_childen.get(&pid).ok_or(SystemError::ECHILD)?.clone();
|
||||
let child_pcb = ProcessManager::find(pid).ok_or(SystemError::ECHILD)?;
|
||||
drop(rd_childen);
|
||||
|
||||
loop {
|
||||
let state = child_pcb.sched_info().state();
|
||||
// 获取退出码
|
||||
match child_pcb.sched_info().state() {
|
||||
match state {
|
||||
ProcessState::Runnable => {
|
||||
if options.contains(WaitOption::WNOHANG)
|
||||
|| options.contains(WaitOption::WNOWAIT)
|
||||
@ -123,12 +144,16 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
ProcessState::Exited(status) => {
|
||||
// kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid);
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(
|
||||
&(status | WaitOption::WEXITED.bits() as usize),
|
||||
&(status as u32 | WaitOption::WEXITED.bits()),
|
||||
0,
|
||||
)?;
|
||||
}
|
||||
drop(child_pcb);
|
||||
// kdebug!("wait4: to release {pid:?}");
|
||||
unsafe { ProcessManager::release(pid) };
|
||||
return Ok(pid.into());
|
||||
}
|
||||
};
|
||||
@ -147,7 +172,8 @@ impl Syscall {
|
||||
} else {
|
||||
// 等待任意子进程(这两)
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
for (pid, pcb) in rd_childen.iter() {
|
||||
for pid in rd_childen.iter() {
|
||||
let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
|
||||
if pcb.sched_info().state().is_exited() {
|
||||
if !wstatus.is_null() {
|
||||
wstatus_buf.copy_one_to_user(&0, 0)?;
|
||||
@ -200,4 +226,73 @@ impl Syscall {
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
return Ok(current_pcb.basic().ppid());
|
||||
}
|
||||
|
||||
pub fn clone(
|
||||
current_trapframe: &mut TrapFrame,
|
||||
clone_args: KernelCloneArgs,
|
||||
) -> Result<usize, SystemError> {
|
||||
let flags = clone_args.flags;
|
||||
|
||||
let vfork = Arc::new(Completion::new());
|
||||
|
||||
if flags.contains(CloneFlags::CLONE_PIDFD)
|
||||
&& flags.contains(CloneFlags::CLONE_PARENT_SETTID)
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
let new_kstack = KernelStack::new()?;
|
||||
let name = current_pcb.basic().name().to_string();
|
||||
let pcb = ProcessControlBlock::new(name, new_kstack);
|
||||
// 克隆pcb
|
||||
ProcessManager::copy_process(¤t_pcb, &pcb, clone_args, current_trapframe)?;
|
||||
ProcessManager::add_pcb(pcb.clone());
|
||||
|
||||
// 向procfs注册进程
|
||||
procfs_register_pid(pcb.pid()).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to register pid to procfs, pid: [{:?}]. Error: {:?}",
|
||||
pcb.pid(),
|
||||
e
|
||||
)
|
||||
});
|
||||
|
||||
if flags.contains(CloneFlags::CLONE_VFORK) {
|
||||
pcb.thread.write().vfork_done = Some(vfork.clone());
|
||||
}
|
||||
|
||||
if pcb.thread.read().set_child_tid.is_some() {
|
||||
let addr = pcb.thread.read().set_child_tid.unwrap();
|
||||
let mut writer =
|
||||
UserBufferWriter::new(addr.as_ptr::<i32>(), core::mem::size_of::<i32>(), true)?;
|
||||
writer.copy_one_to_user(&(pcb.pid().data() as i32), 0)?;
|
||||
}
|
||||
|
||||
ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}",
|
||||
pcb.pid(),
|
||||
e
|
||||
)
|
||||
});
|
||||
|
||||
if flags.contains(CloneFlags::CLONE_VFORK) {
|
||||
// 等待子进程结束或者exec;
|
||||
vfork.wait_for_completion_interruptible()?;
|
||||
}
|
||||
|
||||
return Ok(pcb.pid().0);
|
||||
}
|
||||
|
||||
/// 设置线程地址
|
||||
pub fn set_tid_address(ptr: usize) -> Result<usize, SystemError> {
|
||||
if !unsafe { verify_area(ptr as u64, core::mem::size_of::<i32>() as u64) } {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
pcb.thread.write().clear_child_tid = Some(VirtAddr::new(ptr));
|
||||
Ok(pcb.pid.0)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user