mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 11:16:47 +00:00
* 解决由于spinlock.h中包含preempt_enable()带来的循环include问题 * new: 初步实现signal的数据结构 * new:signal相关数据结构 * fix: 解决bindings.rs报一堆警告的问题 * new: rust下的kdebug kinfo kwarn kBUG kerror宏 * 移动asm.h和cmpxchg.h * new: signal的发送(暂时只支持父子进程共享信号及处理函数)
403 lines
13 KiB
Rust
403 lines
13 KiB
Rust
use core::ptr::read_volatile;
|
||
|
||
use crate::{
|
||
include::{
|
||
bindings::bindings::{
|
||
pid_t, process_control_block, process_find_pcb_by_pid, pt_regs, spinlock_t, EINVAL,
|
||
ENOTSUP, ESRCH, PF_EXITING, PF_KTHREAD, PF_WAKEKILL, PROC_INTERRUPTIBLE,
|
||
},
|
||
DragonOS::signal::{
|
||
si_code_val, sighand_struct, siginfo, signal_struct, sigpending, sigset_t,
|
||
SignalNumber, MAX_SIG_NUM, sigaction, sigaction__union_u,
|
||
},
|
||
},
|
||
kBUG, kdebug, kwarn,
|
||
libs::{
|
||
ffi_convert::FFIBind2Rust,
|
||
spinlock::{spin_is_locked, spin_lock_irqsave, spin_unlock_irqrestore},
|
||
},
|
||
println,
|
||
process::{
|
||
pid::PidType,
|
||
process::{process_is_stopped, process_kick, process_wake_up_state},
|
||
},
|
||
};
|
||
|
||
use crate::include::DragonOS::signal::{__siginfo_union, __siginfo_union_data};
|
||
|
||
/// 默认信号处理程序占位符(用于在sighand结构体中的action数组中占位)
|
||
pub static DEFAULT_SIGACTION: sigaction = sigaction{
|
||
_u: sigaction__union_u{
|
||
_sa_handler: None,
|
||
},
|
||
sa_flags:0,
|
||
sa_mask:0,
|
||
sa_restorer:None
|
||
};
|
||
|
||
/// @brief kill系统调用,向指定的进程发送信号
|
||
/// @param regs->r8 pid 要接收信号的进程id
|
||
/// @param regs->r9 sig 信号
|
||
#[no_mangle]
|
||
pub extern "C" fn sys_kill(regs: &pt_regs) -> u64 {
|
||
println!(
|
||
"sys kill, target pid={}, file={}, line={}",
|
||
regs.r8,
|
||
file!(),
|
||
line!()
|
||
);
|
||
|
||
let pid: pid_t = regs.r8 as pid_t;
|
||
let sig: Option<SignalNumber> = SignalNumber::from_i32(regs.r9 as i32);
|
||
if sig.is_none() {
|
||
// 传入的signal数值不合法
|
||
kwarn!("Not a valid signal number");
|
||
return (-(EINVAL as i64)) as u64;
|
||
}
|
||
|
||
// 初始化signal info
|
||
let mut info = siginfo {
|
||
_sinfo: __siginfo_union {
|
||
data: __siginfo_union_data {
|
||
si_signo: sig.unwrap() as i32,
|
||
si_code: si_code_val::SI_USER as i32,
|
||
si_errno: 0,
|
||
reserved: 0,
|
||
_sifields: crate::include::DragonOS::signal::__sifields {
|
||
_kill: crate::include::DragonOS::signal::__sifields__kill { _pid: pid },
|
||
},
|
||
},
|
||
},
|
||
};
|
||
|
||
return signal_kill_something_info(sig.unwrap(), Some(&mut info), pid) as u64;
|
||
}
|
||
|
||
/// 通过kill的方式向目标进程发送信号
|
||
/// @param sig 要发送的信号
|
||
/// @param info 要发送的信息
|
||
/// @param pid 进程id(目前只支持pid>0)
|
||
fn signal_kill_something_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 {
|
||
// 暂时不支持特殊的kill操作
|
||
if pid <= 0 {
|
||
kwarn!("Kill operation not support: pid={}", pid);
|
||
return -(ENOTSUP as i32);
|
||
}
|
||
|
||
// kill单个进程
|
||
return signal_kill_proc_info(sig, info, pid);
|
||
}
|
||
|
||
fn signal_kill_proc_info(sig: SignalNumber, info: Option<&mut siginfo>, pid: pid_t) -> i32 {
|
||
let mut retval: i32 = -(ESRCH as i32);
|
||
|
||
// step1: 当进程管理模块拥有pcblist_lock之后,对其加锁
|
||
|
||
// step2: 根据pid找到pcb
|
||
let pcb = unsafe { process_find_pcb_by_pid(pid).as_mut() };
|
||
|
||
if pcb.is_none() {
|
||
kwarn!("No such process.");
|
||
return retval;
|
||
}
|
||
|
||
println!("Target pcb = {:?}", pcb.as_ref().unwrap());
|
||
|
||
// step3: 调用signal_send_sig_info函数,发送信息
|
||
retval = signal_send_sig_info(sig, info, pcb.unwrap());
|
||
// step4: 解锁
|
||
return retval;
|
||
}
|
||
|
||
/// @brief 验证信号的值是否在范围内
|
||
#[inline]
|
||
fn verify_signal(sig: SignalNumber) -> bool {
|
||
return if (sig as i32) <= MAX_SIG_NUM {
|
||
true
|
||
} else {
|
||
false
|
||
};
|
||
}
|
||
|
||
/// @brief 在发送信号给指定的进程前,做一些权限检查. 检查是否有权限发送
|
||
/// @param sig 要发送的信号
|
||
/// @param info 要发送的信息
|
||
/// @param target_pcb 信号的接收者
|
||
fn signal_send_sig_info(
|
||
sig: SignalNumber,
|
||
info: Option<&mut siginfo>,
|
||
target_pcb: &mut process_control_block,
|
||
) -> i32 {
|
||
kdebug!("signal_send_sig_info");
|
||
// 检查sig是否符合要求,如果不符合要求,则退出。
|
||
if !verify_signal(sig) {
|
||
return -(EINVAL as i32);
|
||
}
|
||
|
||
// 信号符合要求,可以发送
|
||
|
||
let mut retval = -(ESRCH as i32);
|
||
let mut flags: u64 = 0;
|
||
// 如果上锁成功,则发送信号
|
||
if !lock_process_sighand(target_pcb, &mut flags).is_none() {
|
||
// 发送信号
|
||
retval = send_signal_locked(sig, info, target_pcb, PidType::PID);
|
||
|
||
kdebug!("flags=0x{:016x}", flags);
|
||
// 对sighand放锁
|
||
unlock_process_sighand(target_pcb, &flags);
|
||
}
|
||
return retval;
|
||
}
|
||
|
||
/// @brief 对pcb的sighand结构体中的siglock进行加锁,并关闭中断
|
||
/// @param pcb 目标pcb
|
||
/// @param flags 用来保存rflags的变量
|
||
/// @return 指向sighand_struct的可变引用
|
||
fn lock_process_sighand<'a>(
|
||
pcb: &'a mut process_control_block,
|
||
flags: &mut u64,
|
||
) -> Option<&'a mut sighand_struct> {
|
||
kdebug!("lock_process_sighand");
|
||
let x = unsafe { &mut *pcb.sighand };
|
||
|
||
let sighand_ptr = sighand_struct::convert_mut(unsafe { &mut *pcb.sighand });
|
||
// kdebug!("sighand_ptr={:?}", &sighand_ptr);
|
||
if !sighand_ptr.is_some() {
|
||
kBUG!("Sighand ptr of process {pid} is NULL!", pid = pcb.pid);
|
||
return None;
|
||
}else{
|
||
|
||
kdebug!("7777");
|
||
}
|
||
let lock = {&mut sighand_ptr.unwrap().siglock};
|
||
kdebug!("123");
|
||
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
|
||
spin_lock_irqsave(lock, flags);
|
||
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
|
||
kdebug!("locked");
|
||
let ret = unsafe { ((*pcb).sighand as *mut sighand_struct).as_mut() };
|
||
|
||
return ret;
|
||
}
|
||
|
||
/// @brief 对pcb的sighand结构体中的siglock进行放锁,并恢复之前存储的rflags
|
||
/// @param pcb 目标pcb
|
||
/// @param flags 用来保存rflags的变量,将这个值恢复到rflags寄存器中
|
||
fn unlock_process_sighand(pcb: &mut process_control_block, flags: &u64) {
|
||
kdebug!("unlock_process_sighand");
|
||
let lock = unsafe{&mut (*pcb.sighand).siglock};
|
||
kdebug!("lock={:?}", lock);
|
||
spin_unlock_irqrestore(lock, flags);
|
||
kdebug!("lock={}", unsafe{*(lock as *mut spinlock_t as *mut i8)});
|
||
kdebug!("123443");
|
||
}
|
||
|
||
/// @brief 判断是否需要强制发送信号,然后发送信号
|
||
/// 注意,进入该函数前,我们应当对pcb.sighand.siglock加锁。
|
||
///
|
||
/// @return i32 错误码
|
||
fn send_signal_locked(
|
||
sig: SignalNumber,
|
||
info: Option<&mut siginfo>,
|
||
pcb: &mut process_control_block,
|
||
pt: PidType,
|
||
) -> i32 {
|
||
kdebug!("send_signal_locked");
|
||
// 是否强制发送信号
|
||
let mut force_send = false;
|
||
// signal的信息为空
|
||
if info.is_none() {
|
||
// todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号
|
||
} else {
|
||
force_send = unsafe { info.as_ref().unwrap()._sinfo.data }.si_code
|
||
== (si_code_val::SI_KERNEL as i32);
|
||
}
|
||
|
||
kdebug!("force send={}", force_send);
|
||
|
||
return __send_signal_locked(sig, info, pcb, pt, force_send);
|
||
}
|
||
|
||
/// @brief 发送信号
|
||
/// 注意,进入该函数前,我们应当对pcb.sighand.siglock加锁。
|
||
///
|
||
/// @param sig 信号
|
||
/// @param _info 信号携带的信息
|
||
/// @param pcb 目标进程的pcb
|
||
/// @param pt siginfo结构体中,pid字段代表的含义
|
||
/// @return i32 错误码
|
||
fn __send_signal_locked(
|
||
sig: SignalNumber,
|
||
_info: Option<&mut siginfo>,
|
||
pcb: &mut process_control_block,
|
||
pt: PidType,
|
||
_force_send: bool,
|
||
) -> i32 {
|
||
kdebug!("__send_signal_locked");
|
||
let mut retval = 0;
|
||
|
||
// 判断该进入该函数时,是否已经持有了锁
|
||
println!("locked={}",spin_is_locked(unsafe { &(*pcb.sighand).siglock }));
|
||
kdebug!("1234");
|
||
let _pending: Option<&mut sigpending> = sigpending::convert_mut(&mut pcb.sig_pending);
|
||
kdebug!("567");
|
||
|
||
// 如果是kill或者目标pcb是内核线程,则无需获取sigqueue,直接发送信号即可
|
||
if sig == SignalNumber::SIGKILL || (pcb.flags & (PF_KTHREAD as u64)) != 0 {
|
||
complete_signal(sig, pcb, pt);
|
||
} else {
|
||
// todo: 如果是其他信号,则加入到sigqueue内,然后complete_signal
|
||
retval = -(ENOTSUP as i32);
|
||
}
|
||
kdebug!("12342");
|
||
return retval;
|
||
}
|
||
|
||
/// @brief 将信号添加到目标进程的sig_pending。在引入进程组后,本函数还将负责把信号传递给整个进程组。
|
||
///
|
||
/// @param sig 信号
|
||
/// @param pcb 目标pcb
|
||
/// @param pt siginfo结构体中,pid字段代表的含义
|
||
fn complete_signal(sig: SignalNumber, pcb: &mut process_control_block, pt: PidType) {
|
||
// todo: 将信号产生的消息通知到正在监听这个信号的进程(引入signalfd之后,在这里调用signalfd_notify)
|
||
kdebug!("complete_signal");
|
||
// 将这个信号加到目标进程的sig_pending中
|
||
sigset_add(
|
||
sigset_t::convert_mut(&mut pcb.sig_pending.signal).unwrap(),
|
||
sig,
|
||
);
|
||
|
||
// ===== 寻找需要wakeup的目标进程 =====
|
||
// 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。
|
||
// todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。
|
||
|
||
let _signal: Option<&mut signal_struct> = signal_struct::convert_mut(pcb.signal);
|
||
|
||
let mut _target: Option<&mut process_control_block> = None;
|
||
|
||
// 判断目标进程是否想接收这个信号
|
||
if wants_signal(sig, pcb) {
|
||
_target = Some(pcb);
|
||
} else if pt == PidType::PID {
|
||
/*
|
||
* There is just one thread and it does not need to be woken.
|
||
* It will dequeue unblocked signals before it runs again.
|
||
*/
|
||
return;
|
||
} else {
|
||
/*
|
||
* Otherwise try to find a suitable thread.
|
||
* 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。
|
||
*/
|
||
return;
|
||
}
|
||
|
||
// todo:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。
|
||
// todo!();
|
||
|
||
// todo: 到这里,信号已经被放置在共享的pending队列中,我们在这里把目标进程唤醒。
|
||
if _target.is_some() {
|
||
signal_wake_up(pcb, sig == SignalNumber::SIGKILL);
|
||
}
|
||
}
|
||
|
||
/// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。
|
||
/// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。
|
||
/// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。
|
||
#[inline]
|
||
fn wants_signal(sig: SignalNumber, pcb: &process_control_block) -> bool {
|
||
// 如果改进程屏蔽了这个signal,则不能接收
|
||
if sig_is_member(sigset_t::convert_ref(&pcb.sig_blocked).unwrap(), sig) {
|
||
return false;
|
||
}
|
||
|
||
// 如果进程正在退出,则不能接收信号
|
||
if (pcb.flags & (PF_EXITING as u64)) > 0 {
|
||
return false;
|
||
}
|
||
|
||
if sig == SignalNumber::SIGKILL {
|
||
return true;
|
||
}
|
||
|
||
if process_is_stopped(pcb) {
|
||
return false;
|
||
}
|
||
|
||
// todo: 检查目标进程是否正在一个cpu上执行,如果是,则返回true,否则继续检查下一项
|
||
|
||
// 检查目标进程是否有信号正在等待处理,如果是,则返回false,否则返回true
|
||
return !has_sig_pending(pcb);
|
||
}
|
||
|
||
/// @brief 判断指定的信号在sigset中的对应位是否被置位
|
||
/// @return true: 给定的信号在sigset中被置位
|
||
/// @return false: 给定的信号在sigset中没有被置位
|
||
#[inline]
|
||
fn sig_is_member(set: &sigset_t, _sig: SignalNumber) -> bool {
|
||
return if 1 & (set >> ((_sig as u32) - 1)) != 0 {
|
||
true
|
||
} else {
|
||
false
|
||
};
|
||
}
|
||
|
||
/// @brief 将指定的信号在sigset中的对应bit进行置位
|
||
#[inline]
|
||
fn sigset_add(set: &mut sigset_t, _sig: SignalNumber) {
|
||
*set |= 1 << ((_sig as u32) - 1);
|
||
}
|
||
|
||
/// @brief 判断signal的处理是否可能使得整个进程组退出
|
||
/// @return true 可能会导致退出(不一定)
|
||
#[allow(dead_code)]
|
||
#[inline]
|
||
fn sig_fatal(pcb: &process_control_block, sig: SignalNumber) -> bool {
|
||
let handler = unsafe {
|
||
sighand_struct::convert_ref(pcb.sighand).unwrap().action[(sig as usize) - 1]
|
||
._u
|
||
._sa_handler
|
||
};
|
||
|
||
// 如果handler是空,采用默认函数,signal处理可能会导致进程退出。
|
||
if handler.is_none() {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
|
||
// todo: 参照linux的sig_fatal实现完整功能
|
||
}
|
||
|
||
/// @brief 判断某个进程是否有信号正在等待处理
|
||
#[inline]
|
||
fn has_sig_pending(pcb: &process_control_block) -> bool {
|
||
let ptr = &sigpending::convert_ref(&(*pcb).sig_pending).unwrap().signal;
|
||
if unsafe { read_volatile(ptr) } != 0 {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
#[inline]
|
||
fn signal_wake_up(pcb: &mut process_control_block, fatal: bool) {
|
||
let mut state: u64 = 0;
|
||
if fatal {
|
||
state = PF_WAKEKILL as u64;
|
||
}
|
||
signal_wake_up_state(pcb, state);
|
||
}
|
||
|
||
fn signal_wake_up_state(pcb: &mut process_control_block, state: u64) {
|
||
assert!(spin_is_locked(&unsafe { *pcb.sighand }.siglock));
|
||
// todo: 设置线程结构体的标志位为TIF_SIGPENDING
|
||
|
||
// 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核
|
||
if !process_wake_up_state(pcb, state | (PROC_INTERRUPTIBLE as u64)) {
|
||
process_kick(pcb);
|
||
}
|
||
}
|
||
|