os/ipc/
signal.rs

1//! 进程间通讯 - 信号
2//!
3//! 提供软件中断机制,用于发送异步通知给进程
4//! 处理信号的捕获、屏蔽和默认行为.
5//! # 信号投递流程
6//! - **检查:** 内核在返回用户态前,检查私有 `pending` 和共享 `pending`,找到**最高优先级且未被阻塞**的信号 S。
7//! - **投递:** 内核将 S 从 `pending` 队列中移除,构建 S 的上下文,并修改 PC/SP 指向信号处理函数。
8//! - **返回:** 内核退出,任务在用户态执行信号处理函数。
9//! - **循环:** 当信号处理函数执行完毕,通过 `rt_sigreturn` 返回内核后,内核会**再次**进入检查流程。
10//!             此时,它可能会发现队列中还有第二个未决信号,然后开始第二次单次投递。
11
12use bitflags::bitflags;
13
14use crate::{
15    arch::{
16        kernel::cpu,
17        trap::{TrapFrame, sigreturn_trampoline_address},
18    },
19    kernel::{
20        SharedTask, TASK_MANAGER, TaskManagerTrait, TaskState, current_cpu, current_task,
21        exit_process, exit_task_with_block, sleep_task_with_block, wake_up_with_block, yield_task,
22    },
23    pr_err,
24    uapi::signal::*,
25    util::{address::align_down, user_buffer::write_to_user},
26};
27
28/// 信号的动作表
29/// 每个进程拥有一个独立的信号处理动作表,
30/// 用于存储每个信号的处理函数、屏蔽字和标志。
31/// 索引 0 未用,信号编号从 1..=_NSIG
32/// # SAFE:
33/// 该结构体包含裸指针,但其使用受限于内核对任务的锁保护,
34/// 因此可以安全地实现 Send 和 Sync。
35#[derive(Debug, Clone)]
36pub struct SignalHandlerTable {
37    /// 动作数组,索引 0 未用,信号编号从 1..=_NSIG
38    pub actions: [SignalAction; NSIG + 1],
39}
40
41unsafe impl Send for SignalHandlerTable {}
42unsafe impl Sync for SignalHandlerTable {}
43
44impl SignalHandlerTable {
45    /// 创建一个新的进程信号状态,所有信号动作和屏蔽字为空,待处理信号为空
46    pub fn new() -> Self {
47        Self {
48            actions: core::array::from_fn(|_| SignalAction::default()),
49        }
50    }
51
52    /// 设置某个信号的动作
53    pub fn set_action(&mut self, sig: usize, action: SignalAction) {
54        if sig == 0 || sig > NSIG {
55            return;
56        }
57        self.actions[sig] = action;
58    }
59}
60
61/// 找出第一个可投递的信号(未被屏蔽且挂起的信号中编号最小的)
62pub fn first_deliverable_signal(
63    pending_flags: SignalFlags,
64    blocked_mask: SignalFlags,
65) -> Option<SignalFlags> {
66    let deliverable_signals = pending_flags.difference(blocked_mask);
67
68    if deliverable_signals.is_empty() {
69        return None;
70    }
71
72    let signal_bit_index = deliverable_signals.bits().trailing_zeros();
73    if signal_bit_index < NSIG as u32 {
74        let first_sig = SignalFlags::from_bits(1 << signal_bit_index).unwrap();
75        return Some(first_sig);
76    }
77
78    None
79}
80
81#[inline]
82fn handle_one_signal(sig_flag: SignalFlags, action: SignalAction, task: &SharedTask) {
83    let sig_num = signal_from_flag(sig_flag).unwrap();
84
85    match unsafe { action.sa_handler() } as isize {
86        SIG_DFL => match sig_num {
87            NUM_SIGQUIT | NUM_SIGILL | NUM_SIGABRT | NUM_SIGBUS | NUM_SIGFPE | NUM_SIGSEGV
88            | NUM_SIGSYS | NUM_SIGXCPU | NUM_SIGXFSZ => sig_dump(sig_num), // 致命错误,调用退出系统调用或内核退出函数
89
90            NUM_SIGHUP | NUM_SIGINT | NUM_SIGPIPE | NUM_SIGALRM | NUM_SIGTERM | NUM_SIGUSR1
91            | NUM_SIGUSR2 | NUM_SIGSTKFLT | NUM_SIGPROF | NUM_SIGPWR => sig_terminate(sig_num), // 默认终止
92            NUM_SIGKILL => sig_terminate(sig_num), // SIGKILL 总是终止
93            NUM_SIGSTOP | NUM_SIGTSTP | NUM_SIGTTIN | NUM_SIGTTOU => sig_stop(sig_num),
94            NUM_SIGCONT => sig_continue(sig_num),
95            NUM_SIGCHLD | NUM_SIGURG | NUM_SIGWINCH | NUM_SIGIO => sig_ignore(sig_num),
96            _ => panic!("Unhandled signal"),
97        },
98        SIG_IGN => sig_ignore(sig_num),
99        handler_addr => {
100            // 自定义处理器:构造用户栈上下文并跳转
101            // **将 action.mask 传递给安装跳板函数**
102            install_user_signal_trap_frame(
103                task,
104                sig_num,
105                handler_addr,
106                SignalFlags::from_sigset_t(action.sa_mask),
107            );
108        }
109    }
110}
111
112/// 在返回用户态前检查信号并处理
113/// # 说明:
114/// 该函数会检查当前任务的私有和共享待处理信号集合,
115/// 找出第一个可投递的信号并进行处理。
116/// 如果没有可投递的信号,则直接返回。
117pub fn check_signal() {
118    let task = current_task();
119    let (sig_flag, action) = {
120        let mut t = task.lock();
121        let pending_copy = t.pending.clone();
122        let shared_pending_copy = t.shared_pending.lock().clone();
123        let blocked_copy = t.blocked.clone();
124        if let Some(flag) = first_deliverable_signal(pending_copy.signals, blocked_copy) {
125            let num = signal_from_flag(flag).unwrap();
126            let action = {
127                let handlers = t.signal_handlers.lock();
128                handlers.actions[num]
129            };
130            t.pending.signals.remove(flag);
131            (flag, action)
132        } else if let Some(flag) =
133            first_deliverable_signal(shared_pending_copy.signals, blocked_copy)
134        {
135            let num = signal_from_flag(flag).unwrap();
136            let action = {
137                let handlers = t.signal_handlers.lock();
138                handlers.actions[num]
139            };
140            t.shared_pending.lock().signals.remove(flag);
141            (flag, action)
142        } else {
143            return;
144        }
145    };
146
147    handle_one_signal(sig_flag, action, &task);
148}
149
150/// 为信号创建 siginfo_t 结构体
151/// # 参数:
152/// * `flag`: 信号标志
153/// TODO: 填充更多字段
154pub fn create_siginfo_for_signal(flag: SignalFlags) -> SigInfoT {
155    let sig_num = flag.to_signal_number();
156    let mut sig_info = SigInfoT::new();
157    sig_info.si_signo = sig_num as i32;
158    sig_info.si_code = 0;
159    sig_info.si_errno = 0;
160    sig_info
161}
162
163/// 设置信号用户态处理栈帧
164/// # 说明:
165/// 当信号投递时,内核在信号栈上从高地址到低地址通常依次构建以下结构:
166///     1. siginfo_t 结构体。 该结构体包含有关信号的信息(如信号编号、发送者等)。
167///     2. ucontext_t 结构体。 该结构体保存了被信号中断时的处理器状态(寄存器等)。
168///     3. 返回地址: 指向 C 库中的一个特殊函数(称为 sigreturn 或信号 trampoline),而不是直接返回原程序。
169/// 当信号处理函数返回时,它实际上会跳转到栈上的 sigreturn 函数,该函数会调用 rt_sigreturn 系统调用。
170/// 内核接收到这个调用后,会从栈上加载 ucontext_t 结构体,恢复所有保存的寄存器状态,从而使程序恢复到被中断时的执行点。
171/// # 参数:
172/// * `task`: 目标任务
173/// * `sig_num`: 信号编号
174/// * `entry`: 用户信号处理函数入口地址
175/// * `action_mask`: 信号处理函数的屏蔽字
176fn install_user_signal_trap_frame(
177    task: &SharedTask,
178    sig_num: usize,
179    entry: isize,
180    action_mask: SignalFlags,
181) {
182    let mut t = task.lock();
183    let tp = t.trap_frame_ptr.load(core::sync::atomic::Ordering::SeqCst);
184    unsafe {
185        let tf = &mut *tp;
186        let siginfo = create_siginfo_for_signal(SignalFlags::from_signal_num(sig_num).unwrap());
187        let uc = UContextT::new(
188            0,           // TODO: flags未实现
189            0 as *mut _, // TODO: link未实现
190            t.signal_stack.lock().clone(),
191            t.blocked.to_sigset_t(),
192            MContextT::from_trap_frame(tf),
193        );
194        // 构建用户栈帧
195        // TODO: 处理备用信号栈
196        // 内核决定是否使用备用信号栈取决于:
197        // 1. 备用栈已分配和启用
198        // 2. 信号处理动作明确要求使用备用栈
199        // 3. 当前线程不在备用栈上 (防止递归溢出)
200        let mut current_sp = tf.get_sp();
201
202        current_sp = align_down(current_sp, align_of::<SigInfoT>());
203        let sig_info_addr = current_sp - size_of::<SigInfoT>();
204        current_sp = sig_info_addr;
205
206        current_sp = align_down(current_sp, align_of::<UContextT>());
207        let ucontext_addr = current_sp - size_of::<UContextT>();
208        current_sp = ucontext_addr;
209
210        current_sp = align_down(current_sp, align_of::<usize>()) - size_of::<usize>();
211        let return_addr_slot = current_sp;
212
213        // HACK: 保证返回地址和 ucontext_t 结构体地址之间没有间隙
214        //       以便于在 rt_sigreturn 直接读取 ucontext_t
215        let ucontext_addr = current_sp + size_of::<usize>();
216
217        let final_sp = current_sp;
218
219        write_to_user(sig_info_addr as *mut SigInfoT, siginfo);
220        write_to_user(ucontext_addr as *mut UContextT, uc);
221        write_to_user(
222            return_addr_slot as *mut usize,
223            sigreturn_trampoline_address(),
224        );
225
226        // 更新 blocked(跳过不可屏蔽信号)
227        if sig_num != NUM_SIGKILL && sig_num != NUM_SIGSTOP {
228            let self_flag = SignalFlags::from_bits(1 << (sig_num - 1)).unwrap();
229            t.blocked |= action_mask | self_flag;
230        }
231
232        // 设置用户处理器入口
233        tf.set_sepc(entry as usize);
234        tf.set_a0(sig_num);
235        tf.set_sp(final_sp);
236    }
237}
238
239fn signal_from_flag(flag: SignalFlags) -> Option<usize> {
240    let bit_index = flag.bits().trailing_zeros() as usize;
241
242    if bit_index >= NSIG {
243        return None;
244    }
245
246    Some(bit_index + 1)
247}
248
249/* 默认信号处理函数 */
250/// 默认行为:进程中止
251fn sig_terminate(sig_num: usize) {
252    let tasks = TASK_MANAGER.lock().get_process_threads(current_task());
253    for task in tasks {
254        exit_process(task, (128 + sig_num) as i32);
255    }
256}
257
258/// 默认行为:终止并 Core Dump
259/// TODO: 实现生成 core dump 的功能
260fn sig_dump(sig_num: usize) {
261    pr_err!("signal {}: generating core (stub)", sig_num);
262    sig_terminate(sig_num);
263}
264
265/// 默认行为:停止进程
266fn sig_stop(sig_num: usize) {
267    let pid = current_cpu()
268        .lock()
269        .current_task
270        .clone()
271        .unwrap()
272        .lock()
273        .pid;
274    let tasks = TASK_MANAGER.lock().get_process_threads(current_task());
275    for task in tasks {
276        {
277            let mut t = task.lock();
278            if t.state == TaskState::Zombie {
279                continue;
280            }
281            t.state = TaskState::Stopped;
282        }
283
284        // 从运行队列移除(不可被信号唤醒,外部需用 SIGCONT)
285        sleep_task_with_block(task, false);
286    }
287    yield_task();
288}
289
290/// 默认行为:继续进程
291fn sig_continue(sig_num: usize) {
292    let pid = current_cpu()
293        .lock()
294        .current_task
295        .clone()
296        .unwrap()
297        .lock()
298        .pid;
299    let tasks = TASK_MANAGER.lock().get_process_threads(current_task());
300    for task in tasks {
301        let mut resume = false;
302        {
303            let mut t = task.lock();
304            if t.state == TaskState::Stopped {
305                t.state = TaskState::Running;
306                resume = true;
307            }
308        }
309        if resume {
310            wake_up_with_block(task);
311        }
312    }
313}
314
315/// 默认行为:忽略信号
316fn sig_ignore(sig_num: usize) {}
317
318/// 待处理信号结构体
319#[derive(Debug, Clone)]
320pub struct SignalPending {
321    /// 待处理非实时信号集合
322    pub signals: SignalFlags,
323    // /// 待处理实时信号队列
324    // pub rt_signals: RtSignalQueue,
325}
326
327impl SignalPending {
328    /// 创建一个空的待处理信号集合
329    pub fn empty() -> Self {
330        Self {
331            signals: SignalFlags::empty(),
332            // rt_signals: RtSignalQueue::new(),
333        }
334    }
335
336    /// 检查是否有可投递的信号
337    /// # 参数:
338    /// * `blocked`: 当前阻塞的信号集合
339    pub fn has_deliverable_signal(&self, blocked: SignalFlags) -> bool {
340        !first_deliverable_signal(self.signals, blocked).is_none()
341    }
342
343    /// 获取第一个可投递的信号
344    /// # 参数:
345    /// * `blocked`: 当前阻塞的信号集合
346    pub fn first_deliverable_signal(&self, blocked: SignalFlags) -> Option<SignalFlags> {
347        first_deliverable_signal(self.signals, blocked)
348    }
349
350    /// 获取第一个在目标信号集合中的信号
351    /// # 参数:
352    /// * `target`: 目标信号集合
353    pub fn first_target_signal(&self, target: SignalFlags) -> Option<SignalFlags> {
354        let intersect = self.signals & target;
355        if intersect.is_empty() {
356            return None;
357        }
358
359        let signal_bit_index = intersect.bits().trailing_zeros();
360        if signal_bit_index < NSIG as u32 {
361            let first_sig = SignalFlags::from_bits(1 << signal_bit_index).unwrap();
362            return Some(first_sig);
363        }
364
365        None
366    }
367}
368
369/// 获取当前任务的待处理信号集合(私有 + 共享)
370pub fn do_sigpending() -> SignalFlags {
371    let task = current_task();
372    let t = task.lock();
373    t.pending.signals | t.shared_pending.lock().signals
374}
375
376/// 检查任务是否有可投递的信号
377/// # 参数:
378/// * `task`: 目标任务
379pub fn signal_pending(task: &SharedTask) -> bool {
380    let t = task.lock();
381    t.pending.has_deliverable_signal(t.blocked)
382        || t.shared_pending.lock().has_deliverable_signal(t.blocked)
383}