ソースを参照

Feat(process): 增加ProcessGroup以及Session机制 (#1115)

* 添加make run-nographic

* 添加session和processgroup结构体

* 添加一些有关进程组的syscall

* 在fork中加入set_group

* 修改broadcast未实现的信息

* 添加对kill缺失的进程组的逻辑的补充
火花 1 日 前
コミット
fcb5bf4496

+ 5 - 0
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构建并运行"

+ 1 - 7
docs/community/contact/index.rst

@@ -30,10 +30,4 @@ DragonOS是一个开源项目,我们欢迎任何形式的赞助和捐赠,您
 财务及捐赠信息公开
 -------------------------
 
-DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。
-
-社区管理、财务及法务主体
--------------------------
-
-灵高是DragonOS社区为满足相关监管合规要求,成立的 **非营利性质** 的单位。详情请见:https://ringotek.com.cn
-
+DragonOS社区的捐赠信息将按年进行公开。赞助商、赞助者信息将在收到赞助后,15天内进行公开。

+ 2 - 0
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`

+ 7 - 7
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::<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");
                 }

+ 5 - 4
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(&current.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);
             }

+ 1 - 1
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) {

+ 83 - 10
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<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 = sig
-            .send_signal_info(Some(&mut info), pid)
-            .map(|x| x as usize);
+        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),
+        };
 
-        compiler_fence(core::sync::atomic::Ordering::SeqCst);
+        // compiler_fence(core::sync::atomic::Ordering::SeqCst);
 
         return retval;
     }

+ 1 - 0
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) };

+ 64 - 3
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<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(())
+    }
 }

+ 71 - 8
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<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 - 0
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<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 - 0
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<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);
+    }
+}

+ 65 - 5
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<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(&current_pcb, &pcb, clone_args, current_trapframe)?;
-        ProcessManager::add_pcb(pcb.clone());
 
         // 向procfs注册进程
         procfs_register_pid(pcb.pid()).unwrap_or_else(|e| {

+ 8 - 8
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;

+ 1 - 0
user/apps/test-processgroup/.gitignore

@@ -0,0 +1 @@
+test-processgroup

+ 20 - 0
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:

+ 87 - 0
user/apps/test-processgroup/main.c

@@ -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 - 0
user/apps/test-session/.gitignore

@@ -0,0 +1 @@
+test-session

+ 20 - 0
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:

+ 77 - 0
user/apps/test-session/main.c

@@ -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 - 0
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]]部分

+ 47 - 0
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]]部分