mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 10:15:03 +00:00
Feat(process): 增加ProcessGroup以及Session机制 (#1115)
* 添加make run-nographic * 添加session和processgroup结构体 * 添加一些有关进程组的syscall * 在fork中加入set_group * 修改broadcast未实现的信息 * 添加对kill缺失的进程组的逻辑的补充
This commit is contained in:
parent
50bbcae01a
commit
fcb5bf4496
5
Makefile
5
Makefile
@ -141,6 +141,11 @@ run-vnc: check_arch
|
||||
$(MAKE) write_diskimage || exit 1
|
||||
$(MAKE) qemu-vnc
|
||||
|
||||
run-nographic: check_arch
|
||||
$(MAKE) all -j $(NPROCS)
|
||||
$(MAKE) write_diskimage || exit 1
|
||||
$(MAKE) qemu-nographic
|
||||
|
||||
# 在docker中编译,并启动QEMU
|
||||
run-docker: check_arch
|
||||
@echo "使用docker构建并运行"
|
||||
|
@ -31,9 +31,3 @@ DragonOS是一个开源项目,我们欢迎任何形式的赞助和捐赠,您
|
||||
-------------------------
|
||||
|
||||
DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。
|
||||
|
||||
社区管理、财务及法务主体
|
||||
-------------------------
|
||||
|
||||
灵高是DragonOS社区为满足相关监管合规要求,成立的 **非营利性质** 的单位。详情请见:https://ringotek.com.cn
|
||||
|
||||
|
@ -240,6 +240,8 @@ make run-docker
|
||||
- 本地编译,不运行: `make all -j 您的CPU核心数`
|
||||
- 本地编译,并写入磁盘镜像,不运行: `make build`
|
||||
- 本地编译,写入磁盘镜像,并在QEMU中运行: `make run`
|
||||
- 本地编译,写入磁盘镜像,以无图形模式运行:
|
||||
`make run-nographic`
|
||||
- Docker编译,并写入磁盘镜像,: `make docker`
|
||||
- Docker编译,写入磁盘镜像,并在QEMU中运行: `make run-docker`
|
||||
- 不编译,直接从已有的磁盘镜像启动: `make qemu`
|
||||
|
@ -556,7 +556,7 @@ impl SignalArch for X86_64SignalArch {
|
||||
// 如果当前的rsp不来自用户态,则认为产生了错误(或被SROP攻击)
|
||||
if UserBufferWriter::new(frame, size_of::<SigFrame>(), true).is_err() {
|
||||
error!("rsp doesn't from user level");
|
||||
let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32)
|
||||
let _r = Syscall::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV)
|
||||
.map_err(|e| e.to_posix_errno());
|
||||
return trap_frame.rax;
|
||||
}
|
||||
@ -565,7 +565,7 @@ impl SignalArch for X86_64SignalArch {
|
||||
// 从用户栈恢复sigcontext
|
||||
if !unsafe { &mut (*frame).context }.restore_sigcontext(trap_frame) {
|
||||
error!("unable to restore sigcontext");
|
||||
let _r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32)
|
||||
let _r = Syscall::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV)
|
||||
.map_err(|e| e.to_posix_errno());
|
||||
// 如果这里返回 err 值的话会丢失上一个系统调用的返回值
|
||||
}
|
||||
@ -658,9 +658,9 @@ fn setup_frame(
|
||||
ProcessManager::current_pcb().pid(),
|
||||
sig as i32
|
||||
);
|
||||
let r = Syscall::kill(
|
||||
let r = Syscall::kill_process(
|
||||
ProcessManager::current_pcb().pid(),
|
||||
Signal::SIGSEGV as i32,
|
||||
Signal::SIGSEGV,
|
||||
);
|
||||
if r.is_err() {
|
||||
error!("In setup_sigcontext: generate SIGSEGV signal failed");
|
||||
@ -698,7 +698,7 @@ fn setup_frame(
|
||||
if r.is_err() {
|
||||
// 如果地址区域位于内核空间,则直接报错
|
||||
// todo: 生成一个sigsegv
|
||||
let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32);
|
||||
let r = Syscall::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV);
|
||||
if r.is_err() {
|
||||
error!("In setup frame: generate SIGSEGV signal failed");
|
||||
}
|
||||
@ -709,7 +709,7 @@ fn setup_frame(
|
||||
// 将siginfo拷贝到用户栈
|
||||
info.copy_siginfo_to_user(unsafe { &mut ((*frame).info) as *mut SigInfo })
|
||||
.map_err(|e| -> SystemError {
|
||||
let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32);
|
||||
let r = Syscall::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV);
|
||||
if r.is_err() {
|
||||
error!("In copy_siginfo_to_user: generate SIGSEGV signal failed");
|
||||
}
|
||||
@ -723,7 +723,7 @@ fn setup_frame(
|
||||
.context
|
||||
.setup_sigcontext(oldset, trap_frame)
|
||||
.map_err(|e: SystemError| -> SystemError {
|
||||
let r = Syscall::kill(ProcessManager::current_pcb().pid(), Signal::SIGSEGV as i32);
|
||||
let r = Syscall::kill_process(ProcessManager::current_pcb().pid(), Signal::SIGSEGV);
|
||||
if r.is_err() {
|
||||
error!("In setup_sigcontext: generate SIGSEGV signal failed");
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ impl TtyJobCtrlManager {
|
||||
let mut ctrl = core.contorl_info_irqsave();
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
|
||||
ctrl.session = Some(pcb.basic().sid());
|
||||
let pid = Pid::new(pcb.basic().sid().into());
|
||||
ctrl.session = Some(pid);
|
||||
|
||||
assert!(pcb.sig_info_irqsave().tty().is_none());
|
||||
|
||||
@ -61,7 +62,7 @@ impl TtyJobCtrlManager {
|
||||
}
|
||||
} else {
|
||||
// 暂时使用kill而不是killpg
|
||||
Syscall::kill(pgid, sig as i32)?;
|
||||
Syscall::kill_process(pgid, sig)?;
|
||||
ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.insert(ProcessFlags::HAS_PENDING_SIGNAL);
|
||||
@ -101,12 +102,12 @@ impl TtyJobCtrlManager {
|
||||
if current.sig_info_irqsave().tty().is_none()
|
||||
|| !Arc::ptr_eq(¤t.sig_info_irqsave().tty().clone().unwrap(), &tty)
|
||||
|| ctrl.session.is_none()
|
||||
|| ctrl.session.unwrap() != current.basic().sid()
|
||||
|| ctrl.session.unwrap() != Pid::from(current.basic().sid().into())
|
||||
{
|
||||
return Err(SystemError::ENOTTY);
|
||||
}
|
||||
|
||||
ctrl.pgid = Some(Pid::new(*pgrp as usize));
|
||||
ctrl.pgid = Some(Pid::from(*pgrp as usize));
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
@ -790,7 +790,7 @@ impl NTtyData {
|
||||
let ctrl_info = tty.core().contorl_info_irqsave();
|
||||
let pg = ctrl_info.pgid;
|
||||
if let Some(pg) = pg {
|
||||
let _ = Syscall::kill(pg, signal as i32);
|
||||
let _ = Syscall::kill_process(pg, signal);
|
||||
}
|
||||
|
||||
if !termios.local_mode.contains(LocalMode::NOFLSH) {
|
||||
|
@ -24,7 +24,7 @@ use crate::{
|
||||
ucontext::{AddressSpace, VMA},
|
||||
VirtAddr, VmFlags,
|
||||
},
|
||||
process::{Pid, ProcessManager},
|
||||
process::{process_group::Pgid, Pid, ProcessManager},
|
||||
syscall::{
|
||||
user_access::{UserBufferReader, UserBufferWriter},
|
||||
Syscall,
|
||||
@ -41,6 +41,34 @@ use super::{
|
||||
},
|
||||
};
|
||||
|
||||
/// ### pid转换器,将输入的id转换成对应的pid或pgid
|
||||
/// - 如果id < -1,则为pgid
|
||||
/// - 如果id == -1,则为所有进程
|
||||
/// - 如果id == 0,则为当前进程组
|
||||
/// - 如果id > 0,则为pid
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PidConverter {
|
||||
All,
|
||||
Pid(Pid),
|
||||
Pgid(Pgid),
|
||||
}
|
||||
|
||||
impl PidConverter {
|
||||
/// ### 为 `wait` 和 `kill` 调用使用
|
||||
pub fn from_id(id: i32) -> Self {
|
||||
if id < -1 {
|
||||
PidConverter::Pgid(Pgid::from(-id as usize))
|
||||
} else if id == -1 {
|
||||
PidConverter::All
|
||||
} else if id == 0 {
|
||||
let pgid = ProcessManager::current_pcb().pgid();
|
||||
PidConverter::Pgid(pgid)
|
||||
} else {
|
||||
PidConverter::Pid(Pid::from(id as usize))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Syscall {
|
||||
/// # 创建带参数的匿名管道
|
||||
///
|
||||
@ -92,7 +120,53 @@ impl Syscall {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn kill(pid: Pid, sig: c_int) -> Result<usize, SystemError> {
|
||||
/// ### 杀死一个进程
|
||||
pub fn kill_process(pid: Pid, sig: Signal) -> Result<usize, SystemError> {
|
||||
// 初始化signal info
|
||||
let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let ret = sig
|
||||
.send_signal_info(Some(&mut info), pid)
|
||||
.map(|x| x as usize);
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// ### 杀死一个进程组
|
||||
pub fn kill_process_group(pgid: Pgid, sig: Signal) -> Result<usize, SystemError> {
|
||||
let pg = ProcessManager::find_process_group(pgid).ok_or(SystemError::ESRCH)?;
|
||||
let inner = pg.process_group_inner.lock();
|
||||
for pcb in inner.processes.values() {
|
||||
Self::kill_process(pcb.pid(), sig)?;
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// ### 杀死所有进程
|
||||
/// - 该函数会杀死所有进程,除了当前进程和init进程
|
||||
pub fn kill_all(sig: Signal) -> Result<usize, SystemError> {
|
||||
let current_pid = ProcessManager::current_pcb().pid();
|
||||
let all_processes = ProcessManager::get_all_processes();
|
||||
|
||||
for pid in all_processes {
|
||||
if pid == current_pid || pid.data() == 1 {
|
||||
continue;
|
||||
}
|
||||
Self::kill_process(pid, sig)?;
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
/// # kill系统调用函数
|
||||
///
|
||||
/// ## 参数
|
||||
/// - `id`: id,等于0表示当前进程组,等于-1表示所有进程,小于0表示pgid = -id,大于0表示pid = id,
|
||||
/// - `sig`: 信号值
|
||||
pub fn kill(id: i32, sig: c_int) -> Result<usize, SystemError> {
|
||||
let converter = PidConverter::from_id(id);
|
||||
let sig = Signal::from(sig);
|
||||
if sig == Signal::INVALID {
|
||||
// 传入的signal数值不合法
|
||||
@ -100,16 +174,15 @@ impl Syscall {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 初始化signal info
|
||||
let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
|
||||
// compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let retval = match converter {
|
||||
PidConverter::Pid(pid) => Self::kill_process(pid, sig),
|
||||
PidConverter::Pgid(pgid) => Self::kill_process_group(pgid, sig),
|
||||
PidConverter::All => Self::kill_all(sig),
|
||||
};
|
||||
|
||||
let retval = sig
|
||||
.send_signal_info(Some(&mut info), pid)
|
||||
.map(|x| x as usize);
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
// compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -271,6 +271,7 @@ fn do_waitpid(
|
||||
|
||||
kwo.ret_status = status as i32;
|
||||
|
||||
child_pcb.clear_pg_and_session_reference();
|
||||
drop(child_pcb);
|
||||
// debug!("wait4: to release {pid:?}");
|
||||
unsafe { ProcessManager::release(pid) };
|
||||
|
@ -20,7 +20,7 @@ use crate::{
|
||||
|
||||
use super::{
|
||||
kthread::{KernelThreadPcbPrivate, WorkerPrivate},
|
||||
KernelStack, Pid, ProcessControlBlock, ProcessManager,
|
||||
KernelStack, Pgid, Pid, ProcessControlBlock, ProcessManager, Sid,
|
||||
};
|
||||
const MAX_PID_NS_LEVEL: usize = 32;
|
||||
|
||||
@ -179,7 +179,6 @@ impl ProcessManager {
|
||||
);
|
||||
e
|
||||
})?;
|
||||
ProcessManager::add_pcb(pcb.clone());
|
||||
|
||||
// 向procfs注册进程
|
||||
procfs_register_pid(pcb.pid()).unwrap_or_else(|e| {
|
||||
@ -343,6 +342,7 @@ impl ProcessManager {
|
||||
clone_args: KernelCloneArgs,
|
||||
current_trapframe: &TrapFrame,
|
||||
) -> Result<(), SystemError> {
|
||||
// log::debug!("fork: clone_flags: {:?}", clone_args.flags);
|
||||
let clone_flags = clone_args.flags;
|
||||
// 不允许与不同namespace的进程共享根目录
|
||||
|
||||
@ -497,7 +497,8 @@ impl ProcessManager {
|
||||
} else {
|
||||
pcb.thread.write_irqsave().group_leader = Arc::downgrade(pcb);
|
||||
|
||||
let ptr = pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock;
|
||||
let ptr: *mut ProcessControlBlock =
|
||||
pcb.as_ref() as *const ProcessControlBlock as *mut ProcessControlBlock;
|
||||
unsafe {
|
||||
(*ptr).tgid = pcb.pid;
|
||||
}
|
||||
@ -533,8 +534,68 @@ impl ProcessManager {
|
||||
|
||||
// todo: 增加线程组相关的逻辑。 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/fork.c#2437
|
||||
|
||||
Self::copy_group(current_pcb, pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to set the process group for the new pcb, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
sched_cgroup_fork(pcb);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 拷贝进程组信息
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// `parent_pcb` - 父进程
|
||||
/// `child_pcb` - 子进程
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 无
|
||||
fn copy_group(
|
||||
parent_pcb: &Arc<ProcessControlBlock>,
|
||||
child_pcb: &Arc<ProcessControlBlock>,
|
||||
) -> Result<(), SystemError> {
|
||||
if parent_pcb.process_group().is_none() && parent_pcb.pid() == Pid(0) {
|
||||
return Ok(());
|
||||
}
|
||||
let pg = parent_pcb.process_group().unwrap();
|
||||
|
||||
let mut pg_inner = pg.process_group_inner.lock();
|
||||
|
||||
let mut children_writelock = parent_pcb.children.write();
|
||||
|
||||
children_writelock.push(child_pcb.pid());
|
||||
|
||||
pg_inner
|
||||
.processes
|
||||
.insert(child_pcb.pid(), child_pcb.clone());
|
||||
|
||||
// 检查是否已经存在pgid和sid
|
||||
let pgid = Pgid::new(child_pcb.pid().0);
|
||||
let sid = Sid::new(pgid.into());
|
||||
|
||||
if ProcessManager::find_process_group(pgid).is_some() {
|
||||
ProcessManager::remove_process_group(pgid);
|
||||
}
|
||||
if ProcessManager::find_session(sid).is_some() {
|
||||
ProcessManager::remove_session(sid);
|
||||
}
|
||||
|
||||
child_pcb.set_process_group(&pg);
|
||||
|
||||
let mut guard = child_pcb.basic_mut();
|
||||
guard.set_pgid(pg.pgid());
|
||||
drop(guard);
|
||||
//todo 这里应该解除注释,但是每次一到这里就触发调度,然后由于当前进程持有锁的数量不等于0导致panic
|
||||
//
|
||||
// if let Some(session) = pg.session() {
|
||||
// guard.set_sid(session.sid());
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ use alloc::{
|
||||
use cred::INIT_CRED;
|
||||
use hashbrown::HashMap;
|
||||
use log::{debug, error, info, warn};
|
||||
use process_group::{Pgid, ProcessGroup, ALL_PROCESS_GROUP};
|
||||
use session::{Session, Sid, ALL_SESSION};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
@ -43,6 +45,7 @@ use crate::{
|
||||
futex::{Futex, RobustListHead},
|
||||
},
|
||||
lock_free_flags::LockFreeFlags,
|
||||
mutex::Mutex,
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
wait_queue::WaitQueue,
|
||||
@ -78,7 +81,9 @@ pub mod fork;
|
||||
pub mod idle;
|
||||
pub mod kthread;
|
||||
pub mod pid;
|
||||
pub mod process_group;
|
||||
pub mod resource;
|
||||
pub mod session;
|
||||
pub mod stdio;
|
||||
pub mod syscall;
|
||||
pub mod timer;
|
||||
@ -131,6 +136,8 @@ impl ProcessManager {
|
||||
};
|
||||
|
||||
ALL_PROCESS.lock_irqsave().replace(HashMap::new());
|
||||
ALL_PROCESS_GROUP.lock_irqsave().replace(HashMap::new());
|
||||
ALL_SESSION.lock_irqsave().replace(HashMap::new());
|
||||
Self::init_switch_result();
|
||||
Self::arch_init();
|
||||
debug!("process arch init done.");
|
||||
@ -225,6 +232,15 @@ impl ProcessManager {
|
||||
.insert(pcb.pid(), pcb.clone());
|
||||
}
|
||||
|
||||
/// ### 获取所有进程的pid
|
||||
pub fn get_all_processes() -> Vec<Pid> {
|
||||
let mut pids = Vec::new();
|
||||
for (pid, _) in ALL_PROCESS.lock_irqsave().as_ref().unwrap().iter() {
|
||||
pids.push(*pid);
|
||||
}
|
||||
pids
|
||||
}
|
||||
|
||||
/// 唤醒一个进程
|
||||
pub fn wakeup(pcb: &Arc<ProcessControlBlock>) -> Result<(), SystemError> {
|
||||
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
@ -370,7 +386,7 @@ impl ProcessManager {
|
||||
return;
|
||||
}
|
||||
let parent_pcb = r.unwrap();
|
||||
let r = Syscall::kill(parent_pcb.pid(), Signal::SIGCHLD as i32);
|
||||
let r = Syscall::kill_process(parent_pcb.pid(), Signal::SIGCHLD);
|
||||
if r.is_err() {
|
||||
warn!(
|
||||
"failed to send kill signal to {:?}'s parent pcb {:?}",
|
||||
@ -448,6 +464,7 @@ impl ProcessManager {
|
||||
}
|
||||
pcb.sig_info_mut().set_tty(None);
|
||||
|
||||
pcb.clear_pg_and_session_reference();
|
||||
drop(pcb);
|
||||
ProcessManager::exit_notify();
|
||||
}
|
||||
@ -463,6 +480,7 @@ impl ProcessManager {
|
||||
pub unsafe fn release(pid: Pid) {
|
||||
let pcb = ProcessManager::find(pid);
|
||||
if pcb.is_some() {
|
||||
// log::debug!("release pid {}", pid);
|
||||
// let pcb = pcb.unwrap();
|
||||
// 判断该pcb是否在全局没有任何引用
|
||||
// TODO: 当前,pcb的Arc指针存在泄露问题,引用计数不正确,打算在接下来实现debug专用的Arc,方便调试,然后解决这个bug。
|
||||
@ -716,6 +734,9 @@ pub struct ProcessControlBlock {
|
||||
self_ref: Weak<ProcessControlBlock>,
|
||||
|
||||
restart_block: SpinLock<Option<RestartBlock>>,
|
||||
|
||||
/// 进程组
|
||||
process_group: Mutex<Weak<ProcessGroup>>,
|
||||
}
|
||||
|
||||
impl ProcessControlBlock {
|
||||
@ -767,7 +788,14 @@ impl ProcessControlBlock {
|
||||
(Self::generate_pid(), ppid, cwd, cred, tty)
|
||||
};
|
||||
|
||||
let basic_info = ProcessBasicInfo::new(Pid(0), ppid, Pid(0), name, cwd, None);
|
||||
let basic_info = ProcessBasicInfo::new(
|
||||
Pgid::from(pid.into()),
|
||||
ppid,
|
||||
Sid::from(pid.into()),
|
||||
name,
|
||||
cwd,
|
||||
None,
|
||||
);
|
||||
let preempt_count = AtomicUsize::new(0);
|
||||
let flags = unsafe { LockFreeFlags::new(ProcessFlags::empty()) };
|
||||
|
||||
@ -804,6 +832,7 @@ impl ProcessControlBlock {
|
||||
cred: SpinLock::new(cred),
|
||||
self_ref: Weak::new(),
|
||||
restart_block: SpinLock::new(None),
|
||||
process_group: Mutex::new(Weak::new()),
|
||||
};
|
||||
|
||||
pcb.sig_info.write().set_tty(tty);
|
||||
@ -846,6 +875,25 @@ impl ProcessControlBlock {
|
||||
}
|
||||
}
|
||||
|
||||
if pcb.pid() > Pid(0) && !is_idle {
|
||||
let process_group = ProcessGroup::new(pcb.clone());
|
||||
*pcb.process_group.lock() = Arc::downgrade(&process_group);
|
||||
ProcessManager::add_process_group(process_group.clone());
|
||||
|
||||
let session = Session::new(process_group.clone());
|
||||
process_group.process_group_inner.lock().session = Arc::downgrade(&session);
|
||||
session.session_inner.lock().leader = Some(pcb.clone());
|
||||
ProcessManager::add_session(session);
|
||||
|
||||
ProcessManager::add_pcb(pcb.clone());
|
||||
}
|
||||
// log::debug!(
|
||||
// "A new process is created, pid: {:?}, pgid: {:?}, sid: {:?}",
|
||||
// pcb.pid(),
|
||||
// pcb.process_group().unwrap().pgid(),
|
||||
// pcb.session().unwrap().sid()
|
||||
// );
|
||||
|
||||
return pcb;
|
||||
}
|
||||
|
||||
@ -879,6 +927,12 @@ impl ProcessControlBlock {
|
||||
self.preempt_count.store(count, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn contain_child(&self, pid: &Pid) -> bool {
|
||||
let children = self.children.read();
|
||||
return children.contains(pid);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn flags(&self) -> &mut ProcessFlags {
|
||||
return self.flags.get_mut();
|
||||
@ -1167,6 +1221,7 @@ impl Drop for ProcessControlBlock {
|
||||
.retain(|pid| *pid != self.pid());
|
||||
}
|
||||
|
||||
// log::debug!("Drop pid: {:?}", self.pid());
|
||||
drop(irq_guard);
|
||||
}
|
||||
}
|
||||
@ -1210,11 +1265,11 @@ impl ThreadInfo {
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessBasicInfo {
|
||||
/// 当前进程的进程组id
|
||||
pgid: Pid,
|
||||
pgid: Pgid,
|
||||
/// 当前进程的父进程的pid
|
||||
ppid: Pid,
|
||||
/// 当前进程所属会话id
|
||||
sid: Pid,
|
||||
sid: Sid,
|
||||
/// 进程的名字
|
||||
name: String,
|
||||
|
||||
@ -1231,9 +1286,9 @@ pub struct ProcessBasicInfo {
|
||||
impl ProcessBasicInfo {
|
||||
#[inline(never)]
|
||||
pub fn new(
|
||||
pgid: Pid,
|
||||
pgid: Pgid,
|
||||
ppid: Pid,
|
||||
sid: Pid,
|
||||
sid: Sid,
|
||||
name: String,
|
||||
cwd: String,
|
||||
user_vm: Option<Arc<AddressSpace>>,
|
||||
@ -1250,18 +1305,26 @@ impl ProcessBasicInfo {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn pgid(&self) -> Pid {
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
return self.pgid;
|
||||
}
|
||||
|
||||
pub fn set_pgid(&mut self, pgid: Pgid) {
|
||||
self.pgid = pgid;
|
||||
}
|
||||
|
||||
pub fn ppid(&self) -> Pid {
|
||||
return self.ppid;
|
||||
}
|
||||
|
||||
pub fn sid(&self) -> Pid {
|
||||
pub fn sid(&self) -> Sid {
|
||||
return self.sid;
|
||||
}
|
||||
|
||||
pub fn set_sid(&mut self, sid: Sid) {
|
||||
self.sid = sid;
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
return &self.name;
|
||||
}
|
||||
|
347
kernel/src/process/process_group.rs
Normal file
347
kernel/src/process/process_group.rs
Normal file
@ -0,0 +1,347 @@
|
||||
use super::{
|
||||
session::{Session, Sid},
|
||||
Pid, ProcessControlBlock, ProcessManager,
|
||||
};
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
/// 进程组ID
|
||||
pub type Pgid = Pid;
|
||||
|
||||
/// 系统中所有进程组
|
||||
pub static ALL_PROCESS_GROUP: SpinLock<Option<HashMap<Pgid, Arc<ProcessGroup>>>> =
|
||||
SpinLock::new(None);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessGroup {
|
||||
/// 进程组pgid
|
||||
pub pgid: Pgid,
|
||||
pub process_group_inner: SpinLock<PGInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PGInner {
|
||||
pub processes: BTreeMap<Pid, Arc<ProcessControlBlock>>,
|
||||
pub leader: Option<Arc<ProcessControlBlock>>,
|
||||
pub session: Weak<Session>,
|
||||
}
|
||||
|
||||
impl PGInner {
|
||||
pub fn remove_process(&mut self, pid: &Pid) {
|
||||
if let Some(process) = self.processes.remove(pid) {
|
||||
if let Some(leader) = &self.leader {
|
||||
if Arc::ptr_eq(leader, &process) {
|
||||
self.leader = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.processes.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessGroup {
|
||||
pub fn new(pcb: Arc<ProcessControlBlock>) -> Arc<Self> {
|
||||
let pid = pcb.pid();
|
||||
let mut processes = BTreeMap::new();
|
||||
processes.insert(pid, pcb.clone());
|
||||
let inner = PGInner {
|
||||
processes,
|
||||
leader: Some(pcb),
|
||||
session: Weak::new(),
|
||||
};
|
||||
// log::debug!("New ProcessGroup {:?}", pid);
|
||||
|
||||
Arc::new(Self {
|
||||
pgid: pid,
|
||||
process_group_inner: SpinLock::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn contains(&self, pid: Pid) -> bool {
|
||||
self.process_group_inner.lock().processes.contains_key(&pid)
|
||||
}
|
||||
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
self.pgid
|
||||
}
|
||||
|
||||
pub fn leader(&self) -> Option<Arc<ProcessControlBlock>> {
|
||||
self.process_group_inner.lock().leader.clone()
|
||||
}
|
||||
|
||||
pub fn session(&self) -> Option<Arc<Session>> {
|
||||
// log::debug!("Before lock");
|
||||
let guard = self.process_group_inner.lock();
|
||||
// log::debug!("Locking");
|
||||
let session = guard.session.upgrade();
|
||||
drop(guard);
|
||||
// log::debug!("After lock");
|
||||
return session;
|
||||
}
|
||||
|
||||
pub fn broadcast(&self) {
|
||||
unimplemented!("broadcast not supported yet");
|
||||
}
|
||||
|
||||
pub fn sid(&self) -> Sid {
|
||||
if let Some(session) = self.session() {
|
||||
return session.sid();
|
||||
}
|
||||
Sid::from(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ProcessGroup {
|
||||
fn drop(&mut self) {
|
||||
let mut inner = self.process_group_inner.lock();
|
||||
|
||||
if let Some(leader) = inner.leader.take() {
|
||||
// 组长进程仍然在进程列表中,不应该直接销毁
|
||||
if inner.processes.contains_key(&leader.pid()) {
|
||||
inner.leader = Some(leader);
|
||||
}
|
||||
}
|
||||
|
||||
inner.processes.clear();
|
||||
|
||||
if let Some(session) = inner.session.upgrade() {
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
session_inner.process_groups.remove(&self.pgid);
|
||||
|
||||
if session_inner.should_destory() {
|
||||
ProcessManager::remove_session(session.sid());
|
||||
}
|
||||
}
|
||||
// log::debug!("Dropping pg {:?}", self.pgid.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessManager {
|
||||
/// 根据pgid获取进程组
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pgid` : 进程组的pgid
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 如果找到了对应的进程组,那么返回该进程组,否则返回None
|
||||
pub fn find_process_group(pgid: Pgid) -> Option<Arc<ProcessGroup>> {
|
||||
return ALL_PROCESS_GROUP
|
||||
.lock_irqsave()
|
||||
.as_ref()?
|
||||
.get(&pgid)
|
||||
.cloned();
|
||||
}
|
||||
|
||||
/// 向系统中添加一个进程组
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `pg` : Arc<ProcessGroup>
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 无
|
||||
pub fn add_process_group(pg: Arc<ProcessGroup>) {
|
||||
ALL_PROCESS_GROUP
|
||||
.lock_irqsave()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.insert(pg.pgid(), pg.clone());
|
||||
// log::debug!("New ProcessGroup added, pgid: {:?}", pg.pgid());
|
||||
}
|
||||
|
||||
/// 删除一个进程组
|
||||
pub fn remove_process_group(pgid: Pgid) {
|
||||
// log::debug!("Removing pg {:?}", pgid.clone());
|
||||
let mut all_groups = ALL_PROCESS_GROUP.lock_irqsave();
|
||||
if let Some(pg) = all_groups.as_mut().unwrap().remove(&pgid) {
|
||||
// log::debug!("count: {:?}", Arc::strong_count(&pg));
|
||||
if Arc::strong_count(&pg) <= 2 {
|
||||
// 这里 Arc 计数小于等于 2,意味着它只有在 all_groups 里有一个引用,移除后会自动释放
|
||||
drop(pg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessControlBlock {
|
||||
#[inline(always)]
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
if let Some(process_group) = self.process_group.lock().upgrade() {
|
||||
process_group.pgid()
|
||||
} else {
|
||||
Pgid::from(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn process_group(&self) -> Option<Arc<ProcessGroup>> {
|
||||
self.process_group.lock().upgrade()
|
||||
}
|
||||
|
||||
pub fn set_process_group(&self, pg: &Arc<ProcessGroup>) {
|
||||
if let Some(pcb) = self.self_ref.upgrade() {
|
||||
*pcb.process_group.lock() = Arc::downgrade(pg);
|
||||
// log::debug!("pid: {:?} set pgid: {:?}", self.pid(), pg.pgid());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_process_group_leader(&self) -> bool {
|
||||
if let Some(pcb) = self.self_ref.upgrade() {
|
||||
let pg = self.process_group().unwrap();
|
||||
if let Some(leader) = pg.leader() {
|
||||
return Arc::ptr_eq(&pcb, &leader);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 将进程加入到指定pgid的进程组中(无论该进程组是否已经存在)
|
||||
///
|
||||
/// 如果进程组已经存在,则将进程加入到该进程组中
|
||||
/// 如果进程组不存在,则创建一个新的进程组,并将进程加入到该进程组中
|
||||
///
|
||||
/// ## 参数
|
||||
/// `pgid` : 目标进程组的pgid
|
||||
///
|
||||
/// ## 返回值
|
||||
/// 无
|
||||
pub fn join_other_group(&self, pgid: Pgid) -> Result<(), SystemError> {
|
||||
// if let Some(pcb) = self.self_ref.upgrade() {
|
||||
if self.pgid() == pgid {
|
||||
return Ok(());
|
||||
}
|
||||
if self.is_session_leader() {
|
||||
// 会话领导者不能加入其他进程组
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
if let Some(pg) = ProcessManager::find_process_group(pgid) {
|
||||
let session = self.session().unwrap();
|
||||
if !session.contains_process_group(&pg) {
|
||||
// 进程组和进程应该属于同一个会话
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
self.join_specified_group(&pg)?;
|
||||
} else {
|
||||
if pgid != self.pid() {
|
||||
// 进程组不存在,只能加入自己的进程组
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
self.join_new_group()?;
|
||||
}
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 将进程加入到新创建的进程组中
|
||||
fn join_new_group(&self) -> Result<(), SystemError> {
|
||||
let session = self.session().unwrap();
|
||||
let mut self_pg_mut = self.process_group.lock();
|
||||
|
||||
if let Some(old_pg) = self_pg_mut.upgrade() {
|
||||
let mut old_pg_inner = old_pg.process_group_inner.lock();
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
old_pg_inner.remove_process(&self.pid);
|
||||
*self_pg_mut = Weak::new();
|
||||
|
||||
if old_pg_inner.is_empty() {
|
||||
ProcessManager::remove_process_group(old_pg.pgid());
|
||||
assert!(session_inner.process_groups.contains_key(&old_pg.pgid()));
|
||||
session_inner.process_groups.remove(&old_pg.pgid());
|
||||
}
|
||||
}
|
||||
|
||||
let pcb = self.self_ref.upgrade().unwrap();
|
||||
let new_pg = ProcessGroup::new(pcb);
|
||||
let mut new_pg_inner = new_pg.process_group_inner.lock();
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
|
||||
*self_pg_mut = Arc::downgrade(&new_pg);
|
||||
ProcessManager::add_process_group(new_pg.clone());
|
||||
|
||||
new_pg_inner.session = Arc::downgrade(&session);
|
||||
session_inner
|
||||
.process_groups
|
||||
.insert(new_pg.pgid, new_pg.clone());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 将进程加入到指定的进程组中
|
||||
fn join_specified_group(&self, group: &Arc<ProcessGroup>) -> Result<(), SystemError> {
|
||||
let mut self_group = self.process_group.lock();
|
||||
|
||||
let mut group_inner = if let Some(old_pg) = self_group.upgrade() {
|
||||
let (mut old_pg_inner, group_inner) = match old_pg.pgid().cmp(&group.pgid()) {
|
||||
core::cmp::Ordering::Equal => return Ok(()),
|
||||
core::cmp::Ordering::Less => (
|
||||
old_pg.process_group_inner.lock(),
|
||||
group.process_group_inner.lock(),
|
||||
),
|
||||
core::cmp::Ordering::Greater => {
|
||||
let group_inner = group.process_group_inner.lock();
|
||||
let old_pg_inner = old_pg.process_group_inner.lock();
|
||||
(old_pg_inner, group_inner)
|
||||
}
|
||||
};
|
||||
old_pg_inner.remove_process(&self.pid);
|
||||
*self_group = Weak::new();
|
||||
|
||||
if old_pg_inner.is_empty() {
|
||||
ProcessManager::remove_process_group(old_pg.pgid());
|
||||
}
|
||||
group_inner
|
||||
} else {
|
||||
group.process_group_inner.lock()
|
||||
};
|
||||
|
||||
let pcb = self.self_ref.upgrade().unwrap();
|
||||
group_inner.processes.insert(self.pid, pcb);
|
||||
*self_group = Arc::downgrade(group);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// ### 清除自身的进程组以及会话引用(如果有的话),这个方法只能在进程退出时调用
|
||||
pub fn clear_pg_and_session_reference(&self) {
|
||||
if let Some(pg) = self.process_group() {
|
||||
let mut pg_inner = pg.process_group_inner.lock();
|
||||
pg_inner.remove_process(&self.pid());
|
||||
|
||||
if pg_inner.is_empty() {
|
||||
// 如果进程组没有任何进程了,就删除该进程组
|
||||
ProcessManager::remove_process_group(pg.pgid());
|
||||
// log::debug!("clear_pg_reference: {:?}", pg.pgid());
|
||||
|
||||
if let Some(session) = pg_inner.session.upgrade() {
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
session_inner.remove_process_group(&pg.pgid());
|
||||
if session_inner.is_empty() {
|
||||
// 如果会话没有任何进程组了,就删除该会话
|
||||
ProcessManager::remove_session(session.sid());
|
||||
// log::debug!("clear_pg_reference: {:?}", session.sid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(session) = self.session() {
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
if let Some(leader) = &session_inner.leader {
|
||||
if Arc::ptr_eq(leader, &self.self_ref.upgrade().unwrap()) {
|
||||
session_inner.leader = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
220
kernel/src/process/session.rs
Normal file
220
kernel/src/process/session.rs
Normal file
@ -0,0 +1,220 @@
|
||||
use super::{
|
||||
process_group::{Pgid, ProcessGroup},
|
||||
Pid, ProcessControlBlock, ProcessManager,
|
||||
};
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
use alloc::{
|
||||
collections::BTreeMap,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
/// 会话SID
|
||||
pub type Sid = Pid;
|
||||
|
||||
/// 系统中所有会话
|
||||
pub static ALL_SESSION: SpinLock<Option<HashMap<Sid, Arc<Session>>>> = SpinLock::new(None);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Session {
|
||||
pub sid: Sid,
|
||||
pub session_inner: SpinLock<SessionInner>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SessionInner {
|
||||
pub process_groups: BTreeMap<Pgid, Arc<ProcessGroup>>,
|
||||
pub leader: Option<Arc<ProcessControlBlock>>,
|
||||
}
|
||||
|
||||
impl SessionInner {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.process_groups.is_empty()
|
||||
}
|
||||
pub fn remove_process_group(&mut self, pgid: &Pgid) {
|
||||
self.process_groups.remove(pgid);
|
||||
}
|
||||
pub fn remove_process(&mut self, pcb: &Arc<ProcessControlBlock>) {
|
||||
if let Some(leader) = &self.leader {
|
||||
if Arc::ptr_eq(leader, pcb) {
|
||||
self.leader = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn should_destory(&self) -> bool {
|
||||
self.process_groups.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn new(group: Arc<ProcessGroup>) -> Arc<Self> {
|
||||
let sid = group.pgid;
|
||||
let mut process_groups = BTreeMap::new();
|
||||
process_groups.insert(group.pgid, group.clone());
|
||||
let inner = SessionInner {
|
||||
process_groups,
|
||||
leader: None,
|
||||
};
|
||||
// log::debug!("New Session {:?}", sid);
|
||||
Arc::new(Self {
|
||||
sid,
|
||||
session_inner: SpinLock::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sid(&self) -> Sid {
|
||||
self.sid
|
||||
}
|
||||
|
||||
pub fn leader(&self) -> Option<Arc<ProcessControlBlock>> {
|
||||
self.session_inner.lock().leader.clone()
|
||||
}
|
||||
|
||||
// pub fn contains_process_group(&self, pgid: Pgid) -> bool {
|
||||
// self.session_inner.lock().process_groups.contains_key(&pgid)
|
||||
// }
|
||||
|
||||
pub fn contains_process_group(&self, process_group: &Arc<ProcessGroup>) -> bool {
|
||||
self.session_inner
|
||||
.lock()
|
||||
.process_groups
|
||||
.contains_key(&process_group.pgid)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Session {
|
||||
fn drop(&mut self) {
|
||||
let mut session_inner = self.session_inner.lock();
|
||||
session_inner.process_groups.clear();
|
||||
session_inner.leader = None;
|
||||
// log::debug!("Dropping session: {:?}", self.sid());
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessManager {
|
||||
/// 根据sid获取会话
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `sid` : 会话的sid
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 如果找到了对应的会话,那么返回该会话,否则返回None
|
||||
pub fn find_session(sid: Sid) -> Option<Arc<Session>> {
|
||||
return ALL_SESSION.lock_irqsave().as_ref()?.get(&sid).cloned();
|
||||
}
|
||||
|
||||
/// 向系统中添加一个会话
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `session` : Arc<Session>
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 无
|
||||
pub fn add_session(session: Arc<Session>) {
|
||||
ALL_SESSION
|
||||
.lock_irqsave()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.insert(session.sid(), session.clone());
|
||||
// log::debug!("New Session added, sid: {:?}", session.sid());
|
||||
}
|
||||
|
||||
pub fn remove_session(sid: Sid) {
|
||||
// log::debug!("Removing session: {:?}", sid.clone());
|
||||
let mut all_sessions = ALL_SESSION.lock_irqsave();
|
||||
if let Some(session) = all_sessions.as_mut().unwrap().remove(&sid) {
|
||||
if Arc::strong_count(&session) <= 2 {
|
||||
// 这里 Arc 计数为 1,意味着它只有在 all_groups 里有一个引用,移除后会自动释放
|
||||
drop(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessControlBlock {
|
||||
pub fn session(&self) -> Option<Arc<Session>> {
|
||||
let pg = self.process_group()?;
|
||||
pg.session()
|
||||
}
|
||||
|
||||
pub fn is_session_leader(&self) -> bool {
|
||||
if let Some(pcb) = self.self_ref.upgrade() {
|
||||
let session = pcb.session().unwrap();
|
||||
if let Some(leader) = session.leader() {
|
||||
return Arc::ptr_eq(&pcb, &leader);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// 将进程移动到新会话中
|
||||
/// 如果进程已经是会话领导者,则返回当前会话
|
||||
/// 如果不是,则主动创建一个新会话,并将进程移动到新会话中,返回新会话
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// 新会话
|
||||
pub fn go_to_new_session(&self) -> Result<Arc<Session>, SystemError> {
|
||||
if self.is_session_leader() {
|
||||
return Ok(self.session().unwrap());
|
||||
}
|
||||
|
||||
if self.is_process_group_leader() {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
|
||||
let session = self.session().unwrap();
|
||||
|
||||
let mut self_group = self.process_group.lock();
|
||||
if ProcessManager::find_session(self.pid()).is_some() {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
if ProcessManager::find_process_group(self.pid).is_some() {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
if let Some(old_pg) = self_group.upgrade() {
|
||||
let mut old_pg_inner = old_pg.process_group_inner.lock();
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
old_pg_inner.remove_process(&self.pid);
|
||||
*self_group = Weak::new();
|
||||
|
||||
if old_pg_inner.is_empty() {
|
||||
ProcessManager::remove_process_group(old_pg.pgid());
|
||||
assert!(session_inner.process_groups.contains_key(&old_pg.pgid()));
|
||||
session_inner.process_groups.remove(&old_pg.pgid());
|
||||
if session_inner.is_empty() {
|
||||
ProcessManager::remove_session(session.sid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let pcb = self.self_ref.upgrade().unwrap();
|
||||
let new_pg = ProcessGroup::new(pcb.clone());
|
||||
*self_group = Arc::downgrade(&new_pg);
|
||||
ProcessManager::add_process_group(new_pg.clone());
|
||||
|
||||
let new_session = Session::new(new_pg.clone());
|
||||
let mut new_pg_inner = new_pg.process_group_inner.lock();
|
||||
new_pg_inner.session = Arc::downgrade(&new_session);
|
||||
new_session.session_inner.lock().leader = Some(pcb.clone());
|
||||
ProcessManager::add_session(new_session.clone());
|
||||
|
||||
let mut session_inner = session.session_inner.lock();
|
||||
session_inner.remove_process(&pcb);
|
||||
|
||||
Ok(new_session)
|
||||
}
|
||||
|
||||
pub fn sid(&self) -> Sid {
|
||||
if let Some(session) = self.session() {
|
||||
return session.sid();
|
||||
}
|
||||
return Sid::new(0);
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ use super::{
|
||||
exit::kernel_wait4,
|
||||
fork::{CloneFlags, KernelCloneArgs},
|
||||
resource::{RLimit64, RLimitID, RUsage, RUsageWho},
|
||||
KernelStack, Pid, ProcessManager,
|
||||
KernelStack, Pgid, Pid, ProcessManager,
|
||||
};
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, CurrentIrqArch, MMArch},
|
||||
@ -264,14 +264,74 @@ impl Syscall {
|
||||
///
|
||||
/// @return 成功,指定进程的进程组id
|
||||
/// @return 错误,不存在该进程
|
||||
pub fn getpgid(mut pid: Pid) -> Result<Pid, SystemError> {
|
||||
pub fn getpgid(pid: Pid) -> Result<Pgid, SystemError> {
|
||||
if pid == Pid(0) {
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
pid = current_pcb.pid();
|
||||
return Ok(current_pcb.pgid());
|
||||
}
|
||||
let target_proc = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?;
|
||||
return Ok(target_proc.basic().pgid());
|
||||
return Ok(target_proc.pgid());
|
||||
}
|
||||
|
||||
/// 设置指定进程的pgid
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - pid: 指定进程号
|
||||
/// - pgid: 新的进程组号
|
||||
///
|
||||
/// ## 返回值
|
||||
/// 无
|
||||
pub fn setpgid(pid: Pid, pgid: Pgid) -> Result<usize, SystemError> {
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
let pid = if pid == Pid(0) {
|
||||
current_pcb.pid()
|
||||
} else {
|
||||
pid
|
||||
};
|
||||
let pgid = if pgid == Pgid::from(0) {
|
||||
Pgid::from(pid.into())
|
||||
} else {
|
||||
pgid
|
||||
};
|
||||
if pid != current_pcb.pid() && !current_pcb.contain_child(&pid) {
|
||||
return Err(SystemError::ESRCH);
|
||||
}
|
||||
|
||||
if pgid.into() != pid.into() && ProcessManager::find_process_group(pgid).is_none() {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
let pcb = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?;
|
||||
pcb.join_other_group(pgid)?;
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// 创建新的会话
|
||||
pub fn setsid() -> Result<usize, SystemError> {
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let session = pcb.go_to_new_session()?;
|
||||
Ok(session.sid().into())
|
||||
}
|
||||
|
||||
/// 获取指定进程的会话id
|
||||
///
|
||||
/// 若pid为0,则返回当前进程的会话id
|
||||
///
|
||||
/// 若pid不为0,则返回指定进程的会话id
|
||||
pub fn getsid(pid: Pid) -> Result<usize, SystemError> {
|
||||
let session = ProcessManager::current_pcb().session().unwrap();
|
||||
let sid = session.sid().into();
|
||||
if pid == Pid(0) {
|
||||
return Ok(sid);
|
||||
}
|
||||
let pcb = ProcessManager::find(pid).ok_or(SystemError::ESRCH)?;
|
||||
if !Arc::ptr_eq(&session, &pcb.session().unwrap()) {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
return Ok(sid);
|
||||
}
|
||||
|
||||
/// @brief 获取当前进程的父进程id
|
||||
///
|
||||
/// 若为initproc则ppid设置为0
|
||||
@ -297,10 +357,10 @@ impl Syscall {
|
||||
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| {
|
||||
|
@ -12,6 +12,7 @@ use crate::{
|
||||
net::syscall::MsgHdr,
|
||||
process::{
|
||||
fork::KernelCloneArgs,
|
||||
process_group::Pgid,
|
||||
resource::{RLimit64, RUsage},
|
||||
ProcessFlags, ProcessManager,
|
||||
},
|
||||
@ -410,7 +411,7 @@ impl Syscall {
|
||||
Self::unlink(path)
|
||||
}
|
||||
SYS_KILL => {
|
||||
let pid = Pid::new(args[0]);
|
||||
let pid = args[0] as i32;
|
||||
let sig = args[1] as c_int;
|
||||
// debug!("KILL SYSCALL RECEIVED");
|
||||
Self::kill(pid, sig)
|
||||
@ -667,7 +668,7 @@ impl Syscall {
|
||||
}
|
||||
}
|
||||
|
||||
SYS_GETPGID => Self::getpgid(Pid::new(args[0])).map(|pid| pid.into()),
|
||||
SYS_GETPGID => Self::getpgid(Pid::new(args[0])).map(|pgid| pgid.into()),
|
||||
|
||||
SYS_GETPPID => Self::getppid().map(|pid| pid.into()),
|
||||
|
||||
@ -889,8 +890,9 @@ impl Syscall {
|
||||
SYS_PPOLL => Self::ppoll(args[0], args[1] as u32, args[2], args[3]),
|
||||
|
||||
SYS_SETPGID => {
|
||||
warn!("SYS_SETPGID has not yet been implemented");
|
||||
Ok(0)
|
||||
let pid = Pid::new(args[0]);
|
||||
let pgid = Pgid::new(args[1]);
|
||||
Self::setpgid(pid, pgid)
|
||||
}
|
||||
|
||||
SYS_RT_SIGPROCMASK => {
|
||||
@ -953,10 +955,8 @@ impl Syscall {
|
||||
SYS_SETFSUID => Self::setfsuid(args[0]),
|
||||
SYS_SETFSGID => Self::setfsgid(args[0]),
|
||||
|
||||
SYS_SETSID => {
|
||||
warn!("SYS_SETSID has not yet been implemented");
|
||||
Ok(0)
|
||||
}
|
||||
SYS_SETSID => Self::setsid(),
|
||||
SYS_GETSID => Self::getsid(Pid::new(args[0])),
|
||||
|
||||
SYS_GETRUSAGE => {
|
||||
let who = args[0] as c_int;
|
||||
|
1
user/apps/test-processgroup/.gitignore
vendored
Normal file
1
user/apps/test-processgroup/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test-processgroup
|
20
user/apps/test-processgroup/Makefile
Normal file
20
user/apps/test-processgroup/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
ifeq ($(ARCH), x86_64)
|
||||
CROSS_COMPILE=x86_64-linux-musl-
|
||||
else ifeq ($(ARCH), riscv64)
|
||||
CROSS_COMPILE=riscv64-linux-musl-
|
||||
endif
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
|
||||
all: main.c
|
||||
$(CC) -static -o test-processgroup main.c
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
mv test-processgroup $(DADK_CURRENT_BUILD_DIR)/test-processgroup
|
||||
|
||||
clean:
|
||||
rm test-processgroup *.o
|
||||
|
||||
fmt:
|
87
user/apps/test-processgroup/main.c
Normal file
87
user/apps/test-processgroup/main.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define TEST_ASSERT(left, right, success_msg, fail_msg) \
|
||||
do { \
|
||||
if ((left) == (right)) { \
|
||||
printf("[PASS] %s\n", success_msg); \
|
||||
} else { \
|
||||
printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \
|
||||
fail_msg, \
|
||||
(unsigned long)(right), \
|
||||
(unsigned long)(left)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
// 打印进程信息
|
||||
void print_ids(const char *name) {
|
||||
printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n",
|
||||
name,
|
||||
getpid(),
|
||||
getppid(),
|
||||
getpgid(0), // 获取当前进程的 PGID
|
||||
getsid(0)); // 获取当前进程的 SID
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("===== 测试进程组 =====\n");
|
||||
print_ids("Parent");
|
||||
|
||||
// 创建第一个子进程
|
||||
pid_t child1 = fork();
|
||||
if (child1 == 0) {
|
||||
// 子进程1:设置自己的进程组
|
||||
printf("\n[Child1] 子进程启动...\n");
|
||||
print_ids("Child1 (before setpgid)");
|
||||
|
||||
if (setpgid(0, 0) == -1) { // 将自己的 PGID 设置为自己的 PID
|
||||
perror("setpgid failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
print_ids("Child1 (after setpgid)");
|
||||
|
||||
// Assert: PGID 应该等于 PID
|
||||
// assert(getpgid(0) == getpid());
|
||||
TEST_ASSERT(getpgid(0), getpid(), "Successfully set child1 as processgroup leader", "Child1 PGID check failed");
|
||||
|
||||
sleep(2); // 保持运行,便于观察
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// 创建第二个子进程
|
||||
pid_t child2 = fork();
|
||||
if (child2 == 0) {
|
||||
// 子进程2:加入第一个子进程的进程组
|
||||
printf("\n[Child2] 子进程启动...\n");
|
||||
print_ids("Child2 (before setpgid)");
|
||||
|
||||
if (setpgid(0, child1) == -1) { // 将自己的 PGID 设置为 child1 的 PID
|
||||
perror("setpgid failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
print_ids("Child2 (after setpgid)");
|
||||
|
||||
// Assert: PGID 应该等于 child1 的 PID
|
||||
// assert(getpgid(0) == child1);
|
||||
TEST_ASSERT(getpgid(0),child1,"Child2 PGID is equal to Child1","Child2 PGID check failed");
|
||||
|
||||
sleep(2); // 保持运行,便于观察
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// 父进程:等待子进程结束
|
||||
waitpid(child1, NULL, 0);
|
||||
waitpid(child2, NULL, 0);
|
||||
|
||||
printf("\n[Parent] 所有子进程结束后...\n");
|
||||
print_ids("Parent");
|
||||
|
||||
return 0;
|
||||
}
|
1
user/apps/test-session/.gitignore
vendored
Normal file
1
user/apps/test-session/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
test-session
|
20
user/apps/test-session/Makefile
Normal file
20
user/apps/test-session/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
ifeq ($(ARCH), x86_64)
|
||||
CROSS_COMPILE=x86_64-linux-musl-
|
||||
else ifeq ($(ARCH), riscv64)
|
||||
CROSS_COMPILE=riscv64-linux-musl-
|
||||
endif
|
||||
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
|
||||
all: main.c
|
||||
$(CC) -static -o test-session main.c
|
||||
|
||||
.PHONY: install clean
|
||||
install: all
|
||||
mv test-session $(DADK_CURRENT_BUILD_DIR)/test-session
|
||||
|
||||
clean:
|
||||
rm test-session *.o
|
||||
|
||||
fmt:
|
77
user/apps/test-session/main.c
Normal file
77
user/apps/test-session/main.c
Normal file
@ -0,0 +1,77 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#define TEST_ASSERT(left, right, success_msg, fail_msg) \
|
||||
do { \
|
||||
if ((left) == (right)) { \
|
||||
printf("[PASS] %s\n", success_msg); \
|
||||
} else { \
|
||||
printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \
|
||||
fail_msg, \
|
||||
(unsigned long)(right), \
|
||||
(unsigned long)(left)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define TEST_CONDITION(condition, success_msg, fail_msg) \
|
||||
do { \
|
||||
if (condition) { \
|
||||
printf("[PASS] %s\n", success_msg); \
|
||||
} else { \
|
||||
printf("[FAIL] %s\n", fail_msg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// 打印进程信息
|
||||
void print_ids(const char *name) {
|
||||
printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n",
|
||||
name,
|
||||
getpid(),
|
||||
getppid(),
|
||||
getpgid(0), // 获取当前进程的 PGID
|
||||
getsid(0)); // 获取当前进程的 SID
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf("===== 测试 getsid =====\n");
|
||||
print_ids("Parent");
|
||||
|
||||
pid_t child = fork();
|
||||
if (child == 0) {
|
||||
// 子进程
|
||||
printf("\n[Child] 子进程启动...\n");
|
||||
print_ids("Child (before setsid)");
|
||||
|
||||
// 创建新会话
|
||||
pid_t newsid = setsid();
|
||||
if (newsid == -1) {
|
||||
perror("setsid failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("[Child] 创建新会话成功,新 SID = %d\n", newsid);
|
||||
print_ids("Child (after setsid)");
|
||||
|
||||
TEST_ASSERT(newsid, getpid(), "New sid equal to child pid", "failed to set new sid");
|
||||
TEST_ASSERT(getsid(0), getpid(), "Child sid equal to child pid", "failed to set new sid");
|
||||
TEST_ASSERT(getpgid(0), getpid(), "Child pgid equal to child pid", "failed to set new sid");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} else if (child > 0) {
|
||||
// 父进程
|
||||
waitpid(child, NULL, 0); // 等待子进程结束
|
||||
printf("\n[Parent] 子进程结束后...\n");
|
||||
print_ids("Parent");
|
||||
|
||||
TEST_CONDITION(getsid(0)!=child, "Parent sid unchanged", "Parent sid changed");
|
||||
TEST_CONDITION(getpgid(0)!=child, "Parent pgid unchanged", "Parent pgid changed");
|
||||
} else {
|
||||
perror("fork failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
47
user/dadk/config/test_processgroup_0_1_0.toml
Normal file
47
user/dadk/config/test_processgroup_0_1_0.toml
Normal file
@ -0,0 +1,47 @@
|
||||
# 用户程序名称
|
||||
name = "test-processgroup"
|
||||
|
||||
# 版本号
|
||||
version = "0.1.0"
|
||||
|
||||
# 用户程序描述信息
|
||||
description = "测试进程组的系统调用"
|
||||
|
||||
# 是否只构建一次
|
||||
build-once = false
|
||||
|
||||
# 是否只安装一次
|
||||
install-once = false
|
||||
|
||||
# 目标架构
|
||||
target-arch = ["x86_64"]
|
||||
|
||||
# 任务源
|
||||
[task-source]
|
||||
# 构建类型
|
||||
type = "build-from-source"
|
||||
# 构建来源
|
||||
source = "local"
|
||||
# 路径或URL
|
||||
source-path = "user/apps/test-processgroup"
|
||||
|
||||
# 构建相关信息
|
||||
[build]
|
||||
# 构建命令
|
||||
build-command = "make install -j $(nproc)"
|
||||
|
||||
# 安装相关信息
|
||||
[install]
|
||||
# 安装到DragonOS的路径
|
||||
in-dragonos-path = "/bin"
|
||||
|
||||
# 清除相关信息
|
||||
[clean]
|
||||
# 清除命令
|
||||
clean-command = "make clean"
|
||||
|
||||
# 依赖项
|
||||
# 注意:因为没有依赖项,所以这里不包含[[depends]]部分
|
||||
|
||||
# 环境变量
|
||||
# 注意:因为没有环境变量,所以这里不包含[[envs]]部分
|
47
user/dadk/config/test_session_0_1_0.toml
Normal file
47
user/dadk/config/test_session_0_1_0.toml
Normal file
@ -0,0 +1,47 @@
|
||||
# 用户程序名称
|
||||
name = "test-session"
|
||||
|
||||
# 版本号
|
||||
version = "0.1.0"
|
||||
|
||||
# 用户程序描述信息
|
||||
description = "测试会话的系统调用"
|
||||
|
||||
# 是否只构建一次
|
||||
build-once = false
|
||||
|
||||
# 是否只安装一次
|
||||
install-once = false
|
||||
|
||||
# 目标架构
|
||||
target-arch = ["x86_64"]
|
||||
|
||||
# 任务源
|
||||
[task-source]
|
||||
# 构建类型
|
||||
type = "build-from-source"
|
||||
# 构建来源
|
||||
source = "local"
|
||||
# 路径或URL
|
||||
source-path = "user/apps/test-session"
|
||||
|
||||
# 构建相关信息
|
||||
[build]
|
||||
# 构建命令
|
||||
build-command = "make install -j $(nproc)"
|
||||
|
||||
# 安装相关信息
|
||||
[install]
|
||||
# 安装到DragonOS的路径
|
||||
in-dragonos-path = "/bin"
|
||||
|
||||
# 清除相关信息
|
||||
[clean]
|
||||
# 清除命令
|
||||
clean-command = "make clean"
|
||||
|
||||
# 依赖项
|
||||
# 注意:因为没有依赖项,所以这里不包含[[depends]]部分
|
||||
|
||||
# 环境变量
|
||||
# 注意:因为没有环境变量,所以这里不包含[[envs]]部分
|
Loading…
x
Reference in New Issue
Block a user