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

* 添加make run-nographic

* 添加session和processgroup结构体

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

* 在fork中加入set_group

* 修改broadcast未实现的信息

* 添加对kill缺失的进程组的逻辑的补充
This commit is contained in:
火花 2025-04-22 13:22:42 +08:00 committed by GitHub
parent 50bbcae01a
commit fcb5bf4496
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1180 additions and 53 deletions

View File

@ -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构建并运行"

View File

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

View File

@ -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`

View File

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

View File

@ -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);
}

View File

@ -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) {

View File

@ -24,7 +24,7 @@ use crate::{
ucontext::{AddressSpace, VMA},
VirtAddr, VmFlags,
},
process::{Pid, ProcessManager},
process::{process_group::Pgid, Pid, ProcessManager},
syscall::{
user_access::{UserBufferReader, UserBufferWriter},
Syscall,
@ -41,6 +41,34 @@ use super::{
},
};
/// ### pid转换器将输入的id转换成对应的pid或pgid
/// - 如果id < -1则为pgid
/// - 如果id == -1则为所有进程
/// - 如果id == 0则为当前进程组
/// - 如果id > 0则为pid
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PidConverter {
All,
Pid(Pid),
Pgid(Pgid),
}
impl PidConverter {
/// ### 为 `wait` 和 `kill` 调用使用
pub fn from_id(id: i32) -> Self {
if id < -1 {
PidConverter::Pgid(Pgid::from(-id as usize))
} else if id == -1 {
PidConverter::All
} else if id == 0 {
let pgid = ProcessManager::current_pcb().pgid();
PidConverter::Pgid(pgid)
} else {
PidConverter::Pid(Pid::from(id as usize))
}
}
}
impl Syscall {
/// # 创建带参数的匿名管道
///
@ -92,7 +120,53 @@ impl Syscall {
Ok(0)
}
pub fn kill(pid: Pid, sig: c_int) -> Result<usize, SystemError> {
/// ### 杀死一个进程
pub fn kill_process(pid: Pid, sig: Signal) -> Result<usize, SystemError> {
// 初始化signal info
let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let ret = sig
.send_signal_info(Some(&mut info), pid)
.map(|x| x as usize);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return ret;
}
/// ### 杀死一个进程组
pub fn kill_process_group(pgid: Pgid, sig: Signal) -> Result<usize, SystemError> {
let pg = ProcessManager::find_process_group(pgid).ok_or(SystemError::ESRCH)?;
let inner = pg.process_group_inner.lock();
for pcb in inner.processes.values() {
Self::kill_process(pcb.pid(), sig)?;
}
Ok(0)
}
/// ### 杀死所有进程
/// - 该函数会杀死所有进程除了当前进程和init进程
pub fn kill_all(sig: Signal) -> Result<usize, SystemError> {
let current_pid = ProcessManager::current_pcb().pid();
let all_processes = ProcessManager::get_all_processes();
for pid in all_processes {
if pid == current_pid || pid.data() == 1 {
continue;
}
Self::kill_process(pid, sig)?;
}
Ok(0)
}
/// # kill系统调用函数
///
/// ## 参数
/// - `id`: id等于0表示当前进程组等于-1表示所有进程小于0表示pgid = -id大于0表示pid = id
/// - `sig`: 信号值
pub fn kill(id: i32, sig: c_int) -> Result<usize, SystemError> {
let converter = PidConverter::from_id(id);
let sig = Signal::from(sig);
if sig == Signal::INVALID {
// 传入的signal数值不合法
@ -100,16 +174,15 @@ impl Syscall {
return Err(SystemError::EINVAL);
}
// 初始化signal info
let mut info = SigInfo::new(sig, 0, SigCode::User, SigType::Kill(pid));
// compiler_fence(core::sync::atomic::Ordering::SeqCst);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let retval = match converter {
PidConverter::Pid(pid) => Self::kill_process(pid, sig),
PidConverter::Pgid(pgid) => Self::kill_process_group(pgid, sig),
PidConverter::All => Self::kill_all(sig),
};
let retval = sig
.send_signal_info(Some(&mut info), pid)
.map(|x| x as usize);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// compiler_fence(core::sync::atomic::Ordering::SeqCst);
return retval;
}

View File

@ -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) };

View File

@ -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(())
}
}

View File

@ -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;
}

View File

@ -0,0 +1,347 @@
use super::{
session::{Session, Sid},
Pid, ProcessControlBlock, ProcessManager,
};
use crate::libs::spinlock::SpinLock;
use alloc::{
collections::BTreeMap,
sync::{Arc, Weak},
};
use hashbrown::HashMap;
use system_error::SystemError;
/// 进程组ID
pub type Pgid = Pid;
/// 系统中所有进程组
pub static ALL_PROCESS_GROUP: SpinLock<Option<HashMap<Pgid, Arc<ProcessGroup>>>> =
SpinLock::new(None);
#[derive(Debug)]
pub struct ProcessGroup {
/// 进程组pgid
pub pgid: Pgid,
pub process_group_inner: SpinLock<PGInner>,
}
#[derive(Debug)]
pub struct PGInner {
pub processes: BTreeMap<Pid, Arc<ProcessControlBlock>>,
pub leader: Option<Arc<ProcessControlBlock>>,
pub session: Weak<Session>,
}
impl PGInner {
pub fn remove_process(&mut self, pid: &Pid) {
if let Some(process) = self.processes.remove(pid) {
if let Some(leader) = &self.leader {
if Arc::ptr_eq(leader, &process) {
self.leader = None;
}
}
}
}
pub fn is_empty(&self) -> bool {
self.processes.is_empty()
}
}
impl ProcessGroup {
pub fn new(pcb: Arc<ProcessControlBlock>) -> Arc<Self> {
let pid = pcb.pid();
let mut processes = BTreeMap::new();
processes.insert(pid, pcb.clone());
let inner = PGInner {
processes,
leader: Some(pcb),
session: Weak::new(),
};
// log::debug!("New ProcessGroup {:?}", pid);
Arc::new(Self {
pgid: pid,
process_group_inner: SpinLock::new(inner),
})
}
pub fn contains(&self, pid: Pid) -> bool {
self.process_group_inner.lock().processes.contains_key(&pid)
}
pub fn pgid(&self) -> Pgid {
self.pgid
}
pub fn leader(&self) -> Option<Arc<ProcessControlBlock>> {
self.process_group_inner.lock().leader.clone()
}
pub fn session(&self) -> Option<Arc<Session>> {
// log::debug!("Before lock");
let guard = self.process_group_inner.lock();
// log::debug!("Locking");
let session = guard.session.upgrade();
drop(guard);
// log::debug!("After lock");
return session;
}
pub fn broadcast(&self) {
unimplemented!("broadcast not supported yet");
}
pub fn sid(&self) -> Sid {
if let Some(session) = self.session() {
return session.sid();
}
Sid::from(0)
}
}
impl Drop for ProcessGroup {
fn drop(&mut self) {
let mut inner = self.process_group_inner.lock();
if let Some(leader) = inner.leader.take() {
// 组长进程仍然在进程列表中,不应该直接销毁
if inner.processes.contains_key(&leader.pid()) {
inner.leader = Some(leader);
}
}
inner.processes.clear();
if let Some(session) = inner.session.upgrade() {
let mut session_inner = session.session_inner.lock();
session_inner.process_groups.remove(&self.pgid);
if session_inner.should_destory() {
ProcessManager::remove_session(session.sid());
}
}
// log::debug!("Dropping pg {:?}", self.pgid.clone());
}
}
impl ProcessManager {
/// 根据pgid获取进程组
///
/// ## 参数
///
/// - `pgid` : 进程组的pgid
///
/// ## 返回值
///
/// 如果找到了对应的进程组那么返回该进程组否则返回None
pub fn find_process_group(pgid: Pgid) -> Option<Arc<ProcessGroup>> {
return ALL_PROCESS_GROUP
.lock_irqsave()
.as_ref()?
.get(&pgid)
.cloned();
}
/// 向系统中添加一个进程组
///
/// ## 参数
///
/// - `pg` : Arc<ProcessGroup>
///
/// ## 返回值
///
/// 无
pub fn add_process_group(pg: Arc<ProcessGroup>) {
ALL_PROCESS_GROUP
.lock_irqsave()
.as_mut()
.unwrap()
.insert(pg.pgid(), pg.clone());
// log::debug!("New ProcessGroup added, pgid: {:?}", pg.pgid());
}
/// 删除一个进程组
pub fn remove_process_group(pgid: Pgid) {
// log::debug!("Removing pg {:?}", pgid.clone());
let mut all_groups = ALL_PROCESS_GROUP.lock_irqsave();
if let Some(pg) = all_groups.as_mut().unwrap().remove(&pgid) {
// log::debug!("count: {:?}", Arc::strong_count(&pg));
if Arc::strong_count(&pg) <= 2 {
// 这里 Arc 计数小于等于 2意味着它只有在 all_groups 里有一个引用,移除后会自动释放
drop(pg);
}
}
}
}
impl ProcessControlBlock {
#[inline(always)]
pub fn pgid(&self) -> Pgid {
if let Some(process_group) = self.process_group.lock().upgrade() {
process_group.pgid()
} else {
Pgid::from(0)
}
}
#[inline(always)]
pub fn process_group(&self) -> Option<Arc<ProcessGroup>> {
self.process_group.lock().upgrade()
}
pub fn set_process_group(&self, pg: &Arc<ProcessGroup>) {
if let Some(pcb) = self.self_ref.upgrade() {
*pcb.process_group.lock() = Arc::downgrade(pg);
// log::debug!("pid: {:?} set pgid: {:?}", self.pid(), pg.pgid());
}
}
pub fn is_process_group_leader(&self) -> bool {
if let Some(pcb) = self.self_ref.upgrade() {
let pg = self.process_group().unwrap();
if let Some(leader) = pg.leader() {
return Arc::ptr_eq(&pcb, &leader);
}
}
return false;
}
/// 将进程加入到指定pgid的进程组中无论该进程组是否已经存在
///
/// 如果进程组已经存在,则将进程加入到该进程组中
/// 如果进程组不存在,则创建一个新的进程组,并将进程加入到该进程组中
///
/// ## 参数
/// `pgid` : 目标进程组的pgid
///
/// ## 返回值
/// 无
pub fn join_other_group(&self, pgid: Pgid) -> Result<(), SystemError> {
// if let Some(pcb) = self.self_ref.upgrade() {
if self.pgid() == pgid {
return Ok(());
}
if self.is_session_leader() {
// 会话领导者不能加入其他进程组
return Err(SystemError::EPERM);
}
if let Some(pg) = ProcessManager::find_process_group(pgid) {
let session = self.session().unwrap();
if !session.contains_process_group(&pg) {
// 进程组和进程应该属于同一个会话
return Err(SystemError::EPERM);
}
self.join_specified_group(&pg)?;
} else {
if pgid != self.pid() {
// 进程组不存在,只能加入自己的进程组
return Err(SystemError::EPERM);
}
self.join_new_group()?;
}
// }
Ok(())
}
/// 将进程加入到新创建的进程组中
fn join_new_group(&self) -> Result<(), SystemError> {
let session = self.session().unwrap();
let mut self_pg_mut = self.process_group.lock();
if let Some(old_pg) = self_pg_mut.upgrade() {
let mut old_pg_inner = old_pg.process_group_inner.lock();
let mut session_inner = session.session_inner.lock();
old_pg_inner.remove_process(&self.pid);
*self_pg_mut = Weak::new();
if old_pg_inner.is_empty() {
ProcessManager::remove_process_group(old_pg.pgid());
assert!(session_inner.process_groups.contains_key(&old_pg.pgid()));
session_inner.process_groups.remove(&old_pg.pgid());
}
}
let pcb = self.self_ref.upgrade().unwrap();
let new_pg = ProcessGroup::new(pcb);
let mut new_pg_inner = new_pg.process_group_inner.lock();
let mut session_inner = session.session_inner.lock();
*self_pg_mut = Arc::downgrade(&new_pg);
ProcessManager::add_process_group(new_pg.clone());
new_pg_inner.session = Arc::downgrade(&session);
session_inner
.process_groups
.insert(new_pg.pgid, new_pg.clone());
Ok(())
}
/// 将进程加入到指定的进程组中
fn join_specified_group(&self, group: &Arc<ProcessGroup>) -> Result<(), SystemError> {
let mut self_group = self.process_group.lock();
let mut group_inner = if let Some(old_pg) = self_group.upgrade() {
let (mut old_pg_inner, group_inner) = match old_pg.pgid().cmp(&group.pgid()) {
core::cmp::Ordering::Equal => return Ok(()),
core::cmp::Ordering::Less => (
old_pg.process_group_inner.lock(),
group.process_group_inner.lock(),
),
core::cmp::Ordering::Greater => {
let group_inner = group.process_group_inner.lock();
let old_pg_inner = old_pg.process_group_inner.lock();
(old_pg_inner, group_inner)
}
};
old_pg_inner.remove_process(&self.pid);
*self_group = Weak::new();
if old_pg_inner.is_empty() {
ProcessManager::remove_process_group(old_pg.pgid());
}
group_inner
} else {
group.process_group_inner.lock()
};
let pcb = self.self_ref.upgrade().unwrap();
group_inner.processes.insert(self.pid, pcb);
*self_group = Arc::downgrade(group);
Ok(())
}
/// ### 清除自身的进程组以及会话引用(如果有的话),这个方法只能在进程退出时调用
pub fn clear_pg_and_session_reference(&self) {
if let Some(pg) = self.process_group() {
let mut pg_inner = pg.process_group_inner.lock();
pg_inner.remove_process(&self.pid());
if pg_inner.is_empty() {
// 如果进程组没有任何进程了,就删除该进程组
ProcessManager::remove_process_group(pg.pgid());
// log::debug!("clear_pg_reference: {:?}", pg.pgid());
if let Some(session) = pg_inner.session.upgrade() {
let mut session_inner = session.session_inner.lock();
session_inner.remove_process_group(&pg.pgid());
if session_inner.is_empty() {
// 如果会话没有任何进程组了,就删除该会话
ProcessManager::remove_session(session.sid());
// log::debug!("clear_pg_reference: {:?}", session.sid());
}
}
}
}
if let Some(session) = self.session() {
let mut session_inner = session.session_inner.lock();
if let Some(leader) = &session_inner.leader {
if Arc::ptr_eq(leader, &self.self_ref.upgrade().unwrap()) {
session_inner.leader = None;
}
}
}
}
}

View File

@ -0,0 +1,220 @@
use super::{
process_group::{Pgid, ProcessGroup},
Pid, ProcessControlBlock, ProcessManager,
};
use crate::libs::spinlock::SpinLock;
use alloc::{
collections::BTreeMap,
sync::{Arc, Weak},
};
use hashbrown::HashMap;
use system_error::SystemError;
/// 会话SID
pub type Sid = Pid;
/// 系统中所有会话
pub static ALL_SESSION: SpinLock<Option<HashMap<Sid, Arc<Session>>>> = SpinLock::new(None);
#[derive(Debug)]
pub struct Session {
pub sid: Sid,
pub session_inner: SpinLock<SessionInner>,
}
#[derive(Debug)]
pub struct SessionInner {
pub process_groups: BTreeMap<Pgid, Arc<ProcessGroup>>,
pub leader: Option<Arc<ProcessControlBlock>>,
}
impl SessionInner {
pub fn is_empty(&self) -> bool {
self.process_groups.is_empty()
}
pub fn remove_process_group(&mut self, pgid: &Pgid) {
self.process_groups.remove(pgid);
}
pub fn remove_process(&mut self, pcb: &Arc<ProcessControlBlock>) {
if let Some(leader) = &self.leader {
if Arc::ptr_eq(leader, pcb) {
self.leader = None;
}
}
}
pub fn should_destory(&self) -> bool {
self.process_groups.is_empty()
}
}
impl Session {
pub fn new(group: Arc<ProcessGroup>) -> Arc<Self> {
let sid = group.pgid;
let mut process_groups = BTreeMap::new();
process_groups.insert(group.pgid, group.clone());
let inner = SessionInner {
process_groups,
leader: None,
};
// log::debug!("New Session {:?}", sid);
Arc::new(Self {
sid,
session_inner: SpinLock::new(inner),
})
}
pub fn sid(&self) -> Sid {
self.sid
}
pub fn leader(&self) -> Option<Arc<ProcessControlBlock>> {
self.session_inner.lock().leader.clone()
}
// pub fn contains_process_group(&self, pgid: Pgid) -> bool {
// self.session_inner.lock().process_groups.contains_key(&pgid)
// }
pub fn contains_process_group(&self, process_group: &Arc<ProcessGroup>) -> bool {
self.session_inner
.lock()
.process_groups
.contains_key(&process_group.pgid)
}
}
impl Drop for Session {
fn drop(&mut self) {
let mut session_inner = self.session_inner.lock();
session_inner.process_groups.clear();
session_inner.leader = None;
// log::debug!("Dropping session: {:?}", self.sid());
}
}
impl ProcessManager {
/// 根据sid获取会话
///
/// ## 参数
///
/// - `sid` : 会话的sid
///
/// ## 返回值
///
/// 如果找到了对应的会话那么返回该会话否则返回None
pub fn find_session(sid: Sid) -> Option<Arc<Session>> {
return ALL_SESSION.lock_irqsave().as_ref()?.get(&sid).cloned();
}
/// 向系统中添加一个会话
///
/// ## 参数
///
/// - `session` : Arc<Session>
///
/// ## 返回值
///
/// 无
pub fn add_session(session: Arc<Session>) {
ALL_SESSION
.lock_irqsave()
.as_mut()
.unwrap()
.insert(session.sid(), session.clone());
// log::debug!("New Session added, sid: {:?}", session.sid());
}
pub fn remove_session(sid: Sid) {
// log::debug!("Removing session: {:?}", sid.clone());
let mut all_sessions = ALL_SESSION.lock_irqsave();
if let Some(session) = all_sessions.as_mut().unwrap().remove(&sid) {
if Arc::strong_count(&session) <= 2 {
// 这里 Arc 计数为 1意味着它只有在 all_groups 里有一个引用,移除后会自动释放
drop(session);
}
}
}
}
impl ProcessControlBlock {
pub fn session(&self) -> Option<Arc<Session>> {
let pg = self.process_group()?;
pg.session()
}
pub fn is_session_leader(&self) -> bool {
if let Some(pcb) = self.self_ref.upgrade() {
let session = pcb.session().unwrap();
if let Some(leader) = session.leader() {
return Arc::ptr_eq(&pcb, &leader);
}
}
return false;
}
/// 将进程移动到新会话中
/// 如果进程已经是会话领导者,则返回当前会话
/// 如果不是,则主动创建一个新会话,并将进程移动到新会话中,返回新会话
///
/// ## 返回值
///
/// 新会话
pub fn go_to_new_session(&self) -> Result<Arc<Session>, SystemError> {
if self.is_session_leader() {
return Ok(self.session().unwrap());
}
if self.is_process_group_leader() {
return Err(SystemError::EPERM);
}
let session = self.session().unwrap();
let mut self_group = self.process_group.lock();
if ProcessManager::find_session(self.pid()).is_some() {
return Err(SystemError::EPERM);
}
if ProcessManager::find_process_group(self.pid).is_some() {
return Err(SystemError::EPERM);
}
if let Some(old_pg) = self_group.upgrade() {
let mut old_pg_inner = old_pg.process_group_inner.lock();
let mut session_inner = session.session_inner.lock();
old_pg_inner.remove_process(&self.pid);
*self_group = Weak::new();
if old_pg_inner.is_empty() {
ProcessManager::remove_process_group(old_pg.pgid());
assert!(session_inner.process_groups.contains_key(&old_pg.pgid()));
session_inner.process_groups.remove(&old_pg.pgid());
if session_inner.is_empty() {
ProcessManager::remove_session(session.sid());
}
}
}
let pcb = self.self_ref.upgrade().unwrap();
let new_pg = ProcessGroup::new(pcb.clone());
*self_group = Arc::downgrade(&new_pg);
ProcessManager::add_process_group(new_pg.clone());
let new_session = Session::new(new_pg.clone());
let mut new_pg_inner = new_pg.process_group_inner.lock();
new_pg_inner.session = Arc::downgrade(&new_session);
new_session.session_inner.lock().leader = Some(pcb.clone());
ProcessManager::add_session(new_session.clone());
let mut session_inner = session.session_inner.lock();
session_inner.remove_process(&pcb);
Ok(new_session)
}
pub fn sid(&self) -> Sid {
if let Some(session) = self.session() {
return session.sid();
}
return Sid::new(0);
}
}

View File

@ -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| {

View File

@ -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;

View File

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

View File

@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif
CC=$(CROSS_COMPILE)gcc
all: main.c
$(CC) -static -o test-processgroup main.c
.PHONY: install clean
install: all
mv test-processgroup $(DADK_CURRENT_BUILD_DIR)/test-processgroup
clean:
rm test-processgroup *.o
fmt:

View File

@ -0,0 +1,87 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define TEST_ASSERT(left, right, success_msg, fail_msg) \
do { \
if ((left) == (right)) { \
printf("[PASS] %s\n", success_msg); \
} else { \
printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \
fail_msg, \
(unsigned long)(right), \
(unsigned long)(left)); \
} \
} while (0)
// 打印进程信息
void print_ids(const char *name) {
printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n",
name,
getpid(),
getppid(),
getpgid(0), // 获取当前进程的 PGID
getsid(0)); // 获取当前进程的 SID
}
int main() {
printf("===== 测试进程组 =====\n");
print_ids("Parent");
// 创建第一个子进程
pid_t child1 = fork();
if (child1 == 0) {
// 子进程1设置自己的进程组
printf("\n[Child1] 子进程启动...\n");
print_ids("Child1 (before setpgid)");
if (setpgid(0, 0) == -1) { // 将自己的 PGID 设置为自己的 PID
perror("setpgid failed");
exit(EXIT_FAILURE);
}
print_ids("Child1 (after setpgid)");
// Assert: PGID 应该等于 PID
// assert(getpgid(0) == getpid());
TEST_ASSERT(getpgid(0), getpid(), "Successfully set child1 as processgroup leader", "Child1 PGID check failed");
sleep(2); // 保持运行,便于观察
exit(EXIT_SUCCESS);
}
// 创建第二个子进程
pid_t child2 = fork();
if (child2 == 0) {
// 子进程2加入第一个子进程的进程组
printf("\n[Child2] 子进程启动...\n");
print_ids("Child2 (before setpgid)");
if (setpgid(0, child1) == -1) { // 将自己的 PGID 设置为 child1 的 PID
perror("setpgid failed");
exit(EXIT_FAILURE);
}
print_ids("Child2 (after setpgid)");
// Assert: PGID 应该等于 child1 的 PID
// assert(getpgid(0) == child1);
TEST_ASSERT(getpgid(0),child1,"Child2 PGID is equal to Child1","Child2 PGID check failed");
sleep(2); // 保持运行,便于观察
exit(EXIT_SUCCESS);
}
// 父进程:等待子进程结束
waitpid(child1, NULL, 0);
waitpid(child2, NULL, 0);
printf("\n[Parent] 所有子进程结束后...\n");
print_ids("Parent");
return 0;
}

1
user/apps/test-session/.gitignore vendored Normal file
View File

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

View File

@ -0,0 +1,20 @@
ifeq ($(ARCH), x86_64)
CROSS_COMPILE=x86_64-linux-musl-
else ifeq ($(ARCH), riscv64)
CROSS_COMPILE=riscv64-linux-musl-
endif
CC=$(CROSS_COMPILE)gcc
all: main.c
$(CC) -static -o test-session main.c
.PHONY: install clean
install: all
mv test-session $(DADK_CURRENT_BUILD_DIR)/test-session
clean:
rm test-session *.o
fmt:

View File

@ -0,0 +1,77 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define TEST_ASSERT(left, right, success_msg, fail_msg) \
do { \
if ((left) == (right)) { \
printf("[PASS] %s\n", success_msg); \
} else { \
printf("[FAIL] %s: Expected 0x%lx, but got 0x%lx\n", \
fail_msg, \
(unsigned long)(right), \
(unsigned long)(left)); \
} \
} while (0)
#define TEST_CONDITION(condition, success_msg, fail_msg) \
do { \
if (condition) { \
printf("[PASS] %s\n", success_msg); \
} else { \
printf("[FAIL] %s\n", fail_msg); \
} \
} while (0)
// 打印进程信息
void print_ids(const char *name) {
printf("[%s] PID=%d, PPID=%d, PGID=%d, SID=%d\n",
name,
getpid(),
getppid(),
getpgid(0), // 获取当前进程的 PGID
getsid(0)); // 获取当前进程的 SID
}
int main() {
printf("===== 测试 getsid =====\n");
print_ids("Parent");
pid_t child = fork();
if (child == 0) {
// 子进程
printf("\n[Child] 子进程启动...\n");
print_ids("Child (before setsid)");
// 创建新会话
pid_t newsid = setsid();
if (newsid == -1) {
perror("setsid failed");
exit(EXIT_FAILURE);
}
printf("[Child] 创建新会话成功,新 SID = %d\n", newsid);
print_ids("Child (after setsid)");
TEST_ASSERT(newsid, getpid(), "New sid equal to child pid", "failed to set new sid");
TEST_ASSERT(getsid(0), getpid(), "Child sid equal to child pid", "failed to set new sid");
TEST_ASSERT(getpgid(0), getpid(), "Child pgid equal to child pid", "failed to set new sid");
exit(EXIT_SUCCESS);
} else if (child > 0) {
// 父进程
waitpid(child, NULL, 0); // 等待子进程结束
printf("\n[Parent] 子进程结束后...\n");
print_ids("Parent");
TEST_CONDITION(getsid(0)!=child, "Parent sid unchanged", "Parent sid changed");
TEST_CONDITION(getpgid(0)!=child, "Parent pgid unchanged", "Parent pgid changed");
} else {
perror("fork failed");
exit(EXIT_FAILURE);
}
return 0;
}

View File

@ -0,0 +1,47 @@
# 用户程序名称
name = "test-processgroup"
# 版本号
version = "0.1.0"
# 用户程序描述信息
description = "测试进程组的系统调用"
# 是否只构建一次
build-once = false
# 是否只安装一次
install-once = false
# 目标架构
target-arch = ["x86_64"]
# 任务源
[task-source]
# 构建类型
type = "build-from-source"
# 构建来源
source = "local"
# 路径或URL
source-path = "user/apps/test-processgroup"
# 构建相关信息
[build]
# 构建命令
build-command = "make install -j $(nproc)"
# 安装相关信息
[install]
# 安装到DragonOS的路径
in-dragonos-path = "/bin"
# 清除相关信息
[clean]
# 清除命令
clean-command = "make clean"
# 依赖项
# 注意:因为没有依赖项,所以这里不包含[[depends]]部分
# 环境变量
# 注意:因为没有环境变量,所以这里不包含[[envs]]部分

View File

@ -0,0 +1,47 @@
# 用户程序名称
name = "test-session"
# 版本号
version = "0.1.0"
# 用户程序描述信息
description = "测试会话的系统调用"
# 是否只构建一次
build-once = false
# 是否只安装一次
install-once = false
# 目标架构
target-arch = ["x86_64"]
# 任务源
[task-source]
# 构建类型
type = "build-from-source"
# 构建来源
source = "local"
# 路径或URL
source-path = "user/apps/test-session"
# 构建相关信息
[build]
# 构建命令
build-command = "make install -j $(nproc)"
# 安装相关信息
[install]
# 安装到DragonOS的路径
in-dragonos-path = "/bin"
# 清除相关信息
[clean]
# 清除命令
clean-command = "make clean"
# 依赖项
# 注意:因为没有依赖项,所以这里不包含[[depends]]部分
# 环境变量
# 注意:因为没有环境变量,所以这里不包含[[envs]]部分