diff --git a/Makefile b/Makefile index 83254388..7664aeb9 100644 --- a/Makefile +++ b/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构建并运行" diff --git a/docs/community/contact/index.rst b/docs/community/contact/index.rst index 0e529563..15eb596a 100644 --- a/docs/community/contact/index.rst +++ b/docs/community/contact/index.rst @@ -30,10 +30,4 @@ DragonOS是一个开源项目,我们欢迎任何形式的赞助和捐赠,您 财务及捐赠信息公开 ------------------------- -DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。 - -社区管理、财务及法务主体 -------------------------- - -灵高是DragonOS社区为满足相关监管合规要求,成立的 **非营利性质** 的单位。详情请见:https://ringotek.com.cn - +DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。 \ No newline at end of file diff --git a/docs/introduction/build_system.md b/docs/introduction/build_system.md index 8b6cb21c..1e66d16f 100644 --- a/docs/introduction/build_system.md +++ b/docs/introduction/build_system.md @@ -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` diff --git a/kernel/src/arch/x86_64/ipc/signal.rs b/kernel/src/arch/x86_64/ipc/signal.rs index 25e9eed6..619df758 100644 --- a/kernel/src/arch/x86_64/ipc/signal.rs +++ b/kernel/src/arch/x86_64/ipc/signal.rs @@ -556,7 +556,7 @@ impl SignalArch for X86_64SignalArch { // 如果当前的rsp不来自用户态,则认为产生了错误(或被SROP攻击) if UserBufferWriter::new(frame, size_of::(), 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"); } diff --git a/kernel/src/driver/tty/tty_job_control.rs b/kernel/src/driver/tty/tty_job_control.rs index ef242838..7d07ebd3 100644 --- a/kernel/src/driver/tty/tty_job_control.rs +++ b/kernel/src/driver/tty/tty_job_control.rs @@ -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); } diff --git a/kernel/src/driver/tty/tty_ldisc/ntty.rs b/kernel/src/driver/tty/tty_ldisc/ntty.rs index 363fe579..90afe5f7 100644 --- a/kernel/src/driver/tty/tty_ldisc/ntty.rs +++ b/kernel/src/driver/tty/tty_ldisc/ntty.rs @@ -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) { diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs index d121821e..21db609a 100644 --- a/kernel/src/ipc/syscall.rs +++ b/kernel/src/ipc/syscall.rs @@ -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 { + /// ### 杀死一个进程 + pub fn kill_process(pid: Pid, sig: Signal) -> Result { + // 初始化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 { + 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 { + 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 { + 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; } diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 9cc1620d..e2382328 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -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) }; diff --git a/kernel/src/process/fork.rs b/kernel/src/process/fork.rs index ca4e6015..a364b8b8 100644 --- a/kernel/src/process/fork.rs +++ b/kernel/src/process/fork.rs @@ -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, + child_pcb: &Arc, + ) -> 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(()) + } } diff --git a/kernel/src/process/mod.rs b/kernel/src/process/mod.rs index 6018fe59..4dd61252 100644 --- a/kernel/src/process/mod.rs +++ b/kernel/src/process/mod.rs @@ -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 { + 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) -> 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, restart_block: SpinLock>, + + /// 进程组 + process_group: Mutex>, } 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>, @@ -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; } diff --git a/kernel/src/process/process_group.rs b/kernel/src/process/process_group.rs new file mode 100644 index 00000000..1ca9c9bd --- /dev/null +++ b/kernel/src/process/process_group.rs @@ -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>>> = + SpinLock::new(None); + +#[derive(Debug)] +pub struct ProcessGroup { + /// 进程组pgid + pub pgid: Pgid, + pub process_group_inner: SpinLock, +} + +#[derive(Debug)] +pub struct PGInner { + pub processes: BTreeMap>, + pub leader: Option>, + pub session: Weak, +} + +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) -> Arc { + 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> { + self.process_group_inner.lock().leader.clone() + } + + pub fn session(&self) -> Option> { + // 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> { + return ALL_PROCESS_GROUP + .lock_irqsave() + .as_ref()? + .get(&pgid) + .cloned(); + } + + /// 向系统中添加一个进程组 + /// + /// ## 参数 + /// + /// - `pg` : Arc + /// + /// ## 返回值 + /// + /// 无 + pub fn add_process_group(pg: Arc) { + 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> { + self.process_group.lock().upgrade() + } + + pub fn set_process_group(&self, pg: &Arc) { + 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) -> 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; + } + } + } + } +} diff --git a/kernel/src/process/session.rs b/kernel/src/process/session.rs new file mode 100644 index 00000000..d86bebf2 --- /dev/null +++ b/kernel/src/process/session.rs @@ -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>>> = SpinLock::new(None); + +#[derive(Debug)] +pub struct Session { + pub sid: Sid, + pub session_inner: SpinLock, +} + +#[derive(Debug)] +pub struct SessionInner { + pub process_groups: BTreeMap>, + pub leader: Option>, +} + +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) { + 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) -> Arc { + 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> { + 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) -> 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> { + return ALL_SESSION.lock_irqsave().as_ref()?.get(&sid).cloned(); + } + + /// 向系统中添加一个会话 + /// + /// ## 参数 + /// + /// - `session` : Arc + /// + /// ## 返回值 + /// + /// 无 + pub fn add_session(session: Arc) { + 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> { + 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, 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); + } +} diff --git a/kernel/src/process/syscall.rs b/kernel/src/process/syscall.rs index c2e889bb..5d5d9fa6 100644 --- a/kernel/src/process/syscall.rs +++ b/kernel/src/process/syscall.rs @@ -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 { + pub fn getpgid(pid: Pid) -> Result { 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 { + 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 { + 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 { + 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| { diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 73ef97cd..9ee5f882 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -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; diff --git a/user/apps/test-processgroup/.gitignore b/user/apps/test-processgroup/.gitignore new file mode 100644 index 00000000..2180c4c4 --- /dev/null +++ b/user/apps/test-processgroup/.gitignore @@ -0,0 +1 @@ +test-processgroup \ No newline at end of file diff --git a/user/apps/test-processgroup/Makefile b/user/apps/test-processgroup/Makefile new file mode 100644 index 00000000..56880551 --- /dev/null +++ b/user/apps/test-processgroup/Makefile @@ -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: diff --git a/user/apps/test-processgroup/main.c b/user/apps/test-processgroup/main.c new file mode 100644 index 00000000..ef4e9aad --- /dev/null +++ b/user/apps/test-processgroup/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/user/apps/test-session/.gitignore b/user/apps/test-session/.gitignore new file mode 100644 index 00000000..def31541 --- /dev/null +++ b/user/apps/test-session/.gitignore @@ -0,0 +1 @@ +test-session \ No newline at end of file diff --git a/user/apps/test-session/Makefile b/user/apps/test-session/Makefile new file mode 100644 index 00000000..1ebf48f8 --- /dev/null +++ b/user/apps/test-session/Makefile @@ -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: diff --git a/user/apps/test-session/main.c b/user/apps/test-session/main.c new file mode 100644 index 00000000..c33046e4 --- /dev/null +++ b/user/apps/test-session/main.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/user/dadk/config/test_processgroup_0_1_0.toml b/user/dadk/config/test_processgroup_0_1_0.toml new file mode 100644 index 00000000..619174da --- /dev/null +++ b/user/dadk/config/test_processgroup_0_1_0.toml @@ -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]]部分 diff --git a/user/dadk/config/test_session_0_1_0.toml b/user/dadk/config/test_session_0_1_0.toml new file mode 100644 index 00000000..57e8a335 --- /dev/null +++ b/user/dadk/config/test_session_0_1_0.toml @@ -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]]部分