os/kernel/syscall/
signal.rs

1//! 信号相关的系统调用实现
2
3use core::{
4    ffi::{c_int, c_uint, c_ulong},
5    sync::atomic::Ordering,
6};
7
8use alloc::{sync::Arc, vec::Vec};
9
10use crate::{
11    arch::{timer::clock_freq, trap::restore},
12    ipc::{create_siginfo_for_signal, do_sigpending},
13    kernel::{
14        SharedTask, TASK_MANAGER, TIMER_QUEUE, TaskManagerTrait, current_task,
15        sleep_task_with_guard_and_block, yield_task,
16    },
17    sync::SpinLock,
18    uapi::{
19        errno::{EAGAIN, EINTR, EINVAL, ENOMEM, ENOSYS, ESRCH},
20        signal::{
21            MINSIGSTKSZ, NSIG, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK, SIGSET_SIZE, SS_AUTODISARM,
22            SS_DISABLE, SS_ONSTACK, SaFlags, SigInfoT, SignalAction, SignalFlags, UContextT,
23        },
24        time::TimeSpec,
25        types::{SigSetT, StackT},
26    },
27    util::user_buffer::{read_from_user, write_to_user},
28};
29
30/// 修改当前任务的信号屏蔽字
31/// # 参数:
32/// * `how` - 指示如何修改屏蔽字的操作(SIG_BLOCK、SIG_UNBLOCK、SIG_SETMASK)
33/// * `set` - 指向用户空间缓冲区的指针,包含要设置的信号集合
34/// * `oset` - 指向用户空间缓冲区的指针,用于存放旧的信号集合
35/// # 返回值:
36/// * 成功时返回 0
37/// * 失败时返回负的错误码
38pub fn rt_sigprocmask(
39    how: c_int,
40    set: *const SigSetT,
41    oset: *mut SigSetT,
42    sigsetsize: c_uint,
43) -> c_int {
44    if sigsetsize as usize != SIGSET_SIZE {
45        return -EINVAL;
46    }
47    let task = crate::kernel::current_task();
48    let mut t = task.lock();
49
50    if !oset.is_null() {
51        let old_set = t.blocked.bits() as c_ulong;
52        unsafe {
53            write_to_user(oset, old_set);
54        }
55    }
56
57    if !set.is_null() {
58        let new_set = unsafe { read_from_user(set) };
59        let new_flags = if let Some(flag) = SignalFlags::from_bits(new_set as usize) {
60            flag
61        } else {
62            return -EINVAL;
63        };
64
65        match how {
66            SIG_BLOCK => {
67                t.blocked |= new_flags;
68            }
69            SIG_UNBLOCK => {
70                t.blocked &= !new_flags;
71            }
72            SIG_SETMASK => {
73                t.blocked = new_flags;
74            }
75            _ => {
76                return -EINVAL;
77            }
78        }
79    }
80
81    0
82}
83
84/// 获取当前任务的待处理信号集合, 包括私有和共享的信号集合
85/// # 参数:
86/// * `uset` - 指向用户空间缓冲区的指针,用于存放待处理信号集合
87pub fn rt_sigpending(uset: *mut SigSetT, sigsetsize: c_uint) -> c_int {
88    if sigsetsize as usize != SIGSET_SIZE {
89        return -EINVAL;
90    }
91    let pending = do_sigpending();
92    unsafe {
93        write_to_user(uset, pending.bits() as SigSetT);
94    }
95    0
96}
97
98/// 更改指定信号的处理动作
99/// # 参数:
100/// * `signum` - 信号编号
101/// * `act` - 指向新的 SignalAction 结构体的指针(如果不为 NULL)
102/// * `oldact` - 指向用于存放旧的 SignalAction 结构体的指针(如果不为 NULL)
103/// # 返回值:
104/// * 成功时返回 0
105/// * 失败时返回负的错误码
106pub fn rt_sigaction(signum: c_int, act: *const SignalAction, oldact: *mut SignalAction) -> c_int {
107    if signum <= 0 || signum as usize > NSIG {
108        return -EINVAL;
109    }
110
111    let task = crate::kernel::current_task();
112    let t = task.lock();
113
114    if !oldact.is_null() {
115        let current_action = t.signal_handlers.lock().actions[signum as usize].clone();
116        unsafe {
117            write_to_user(oldact, current_action);
118        }
119    }
120
121    if !act.is_null() {
122        let new_action = unsafe { read_from_user(act) };
123        let flag = if let Some(flag) = SaFlags::from_bits(new_action.sa_flags as u32) {
124            flag
125        } else {
126            return -EINVAL;
127        };
128        if !flag.is_known() {
129            return -EINVAL;
130        }
131        if !flag.is_supported() {
132            return -ENOSYS;
133        }
134        t.signal_handlers
135            .lock()
136            .set_action(signum as usize, new_action);
137    }
138
139    0
140}
141
142/// 实现实时信号等待
143/// # 参数:
144/// * `set` - 指向用户空间缓冲区的指针,包含要等待的信号集合
145/// * `info` - 指向用户空间缓冲区的指针,用于存放信号信息
146/// * `timeout` - 指向用户空间缓冲区的指针,包含超时时间
147/// * `sigsetsize` - 信号集合的大小
148/// # 返回值:
149/// * 成功时返回收到的信号编号
150/// * 失败时返回负的错误码
151pub fn rt_sigtimedwait(
152    set: *const SigSetT,
153    info: *mut SigInfoT,
154    timeout: *const TimeSpec,
155    sigsetsize: c_uint,
156) -> c_int {
157    if sigsetsize as usize != SIGSET_SIZE {
158        return -EINVAL;
159    }
160
161    let wait_set_bits = unsafe { read_from_user(set) };
162    let wait_set = if let Some(flags) = SignalFlags::from_bits(wait_set_bits as usize) {
163        flags
164    } else {
165        return -EINVAL;
166    };
167
168    let timeout_opt = if !timeout.is_null() {
169        let ts = unsafe { read_from_user(timeout) };
170        Some(ts)
171    } else {
172        None
173    };
174
175    match wait_for_signal(current_task(), wait_set, timeout_opt) {
176        Ok((sig_num, sig_info)) => {
177            if !info.is_null() {
178                unsafe {
179                    write_to_user(info, sig_info);
180                }
181            }
182            sig_num as c_int
183        }
184        Err(err_code) => err_code,
185    }
186}
187
188/// 实现实时信号挂起
189/// 它将三个独立的操作封装成一个不可分割的原子操作:
190/// 1. 设置新的信号屏蔽字
191/// 2. 挂起当前任务,直到收到信号
192/// 3. 恢复旧的信号屏蔽字
193/// # 参数:
194/// * `unewset` - 指向用户空间缓冲区的指针,包含新的信号集合
195/// * `sigsetsize` - 信号集合的大小
196/// # 返回值:
197/// * 该调用总是被信号中断,返回 -EINTR
198/// * 失败时返回负的错误码
199pub fn rt_sigsuspend(unewset: *const SigSetT, sigsetsize: c_uint) -> c_int {
200    if sigsetsize as usize != SIGSET_SIZE {
201        return -EINVAL;
202    }
203    let new_set_bits = unsafe { read_from_user(unewset) };
204    let new_set = if let Some(flags) = SignalFlags::from_bits(new_set_bits as usize) {
205        flags
206    } else {
207        return -EINVAL;
208    };
209    let task = current_task();
210    let old_set;
211    {
212        let mut t = task.lock();
213        old_set = t.blocked;
214        t.blocked = new_set;
215        sleep_task_with_guard_and_block(&mut t, task.clone(), true);
216    }
217    yield_task();
218    {
219        let mut t = task.lock();
220        t.blocked = old_set;
221    }
222    -EINTR
223}
224
225/// 撤销之前为了调用信号处理程序而进行的所有操作
226/// 利用先前保存在用户空间栈上的信息,
227/// 恢复进程的信号掩码,切换栈,并恢复进程的上下文(处理器标志和寄存器,
228/// 包括栈指针和指令指针),以便进程从被信号中断的位置恢复执行。
229pub fn rt_sigreturn() -> ! {
230    let tfp = current_task().lock().trap_frame_ptr.load(Ordering::SeqCst);
231    let tf = unsafe { &mut *tfp };
232    let ucontext_addr = tf.get_sp();
233    let ucontext: UContextT = unsafe { read_from_user(ucontext_addr as *const UContextT) };
234    tf.restore_from_mcontext(&ucontext.uc_mcontext);
235    unsafe { restore(tf) }
236    unreachable!("rt_sigreturn should not return");
237}
238
239/// 设置或获取备用信号处理栈的信息
240/// # 参数:
241/// * `uss` - 指向用户空间缓冲区的指针,包含新的信号栈信息(如果不为 NULL)
242/// * `uoss` - 指向用户空间缓冲区的指针,用于存放旧的信号栈信息(如果不为 NULL)
243/// # 返回值:
244/// * 成功时返回 0
245/// * 失败时返回负的错误码
246pub fn signal_stack(uss: *const StackT, uoss: *mut StackT) -> c_int {
247    let task = current_task();
248    let mut t = task.lock();
249
250    if !uoss.is_null() {
251        let old_ss = t.signal_stack.lock().clone();
252        unsafe {
253            write_to_user(uoss, old_ss);
254        }
255    }
256
257    if !uss.is_null() {
258        let new_ss = unsafe { read_from_user(uss) };
259        if new_ss.ss_size < MINSIGSTKSZ as u64 {
260            return -ENOMEM;
261        }
262        if new_ss.ss_flags as usize & SS_AUTODISARM & SS_DISABLE & SS_ONSTACK != 0 {
263            return -EINVAL;
264        }
265        t.signal_stack = Arc::new(SpinLock::new(new_ss));
266    }
267    0
268}
269
270/// 向任何进程组或进程发送任何信号。
271/// 如果 pid 为正数,则向 pid 指定的进程发送信号 sig。
272/// 如果 pid 等于 0,则向调用进程所在进程组中的每个进程发送信号 sig。
273/// 如果 pid 等于 -1,则向调用进程有权发送信号的每个进程发送信号 sig,但进程 1(init)除外,
274/// 如果 pid 小于 -1,则向进程组 ID 为 -pid 的每个进程发送信号。
275/// 如果 sig 为 0,则不发送信号,但仍会执行存在性和权限检查;
276/// # 参数:
277/// * `pid` - 目标进程或进程组的 ID
278/// * `sig` - 要发送的信号编号
279/// # 返回值:
280/// * 成功时返回 0
281/// * 失败时返回负的错误码
282pub fn kill(pid: c_int, sig: c_int) -> c_int {
283    if sig < 0 || sig as usize >= NSIG {
284        return -EINVAL;
285    }
286    let task_manager = TASK_MANAGER.lock();
287    let target_tasks: Vec<SharedTask> = match pid {
288        0 => {
289            let current_task = current_task();
290            let pgid = current_task.lock().pgid;
291            task_manager.get_task_cond(|t| {
292                t.lock().pgid == pgid && t.lock().pid != 1 && t.lock().is_process()
293            })
294        }
295        pid if pid > 0 => {
296            if let Some(task) = task_manager.get_task(pid as u32) {
297                if !task.lock().is_process() {
298                    return -EINVAL;
299                }
300                alloc::vec![task]
301            } else {
302                return -ESRCH;
303            }
304        }
305        -1 => task_manager.get_task_cond(|t| t.lock().pid != 1 && t.lock().is_process()),
306        pid if pid < -1 => {
307            let pgid = (-pid) as u32;
308            task_manager.get_task_cond(|t| {
309                t.lock().pgid == pgid && t.lock().pid != 1 && t.lock().is_process()
310            })
311        }
312        _ => alloc::vec![],
313    };
314
315    if target_tasks.is_empty() {
316        return -ESRCH;
317    }
318
319    for task in target_tasks {
320        task_manager.send_signal(task, sig as usize);
321    }
322    0
323}
324
325/// 向线程组 tgid 中线程 ID 为 tid 的线程发送信号 sig.
326/// 注意: 如果线程终止且其线程 ID 被回收,则向错误的线程发送信号。避免使用此系统调用。
327/// # 参数:
328/// * `tid` - 目标线程的 ID
329/// * `sig` - 要发送的信号编号
330/// # 返回值:
331/// * 成功时返回 0
332/// * 失败时返回负的错误码
333pub fn tkill(tid: c_int, sig: c_int) -> c_int {
334    if sig < 0 || sig as usize >= NSIG {
335        return -EINVAL;
336    }
337    let task_manager = TASK_MANAGER.lock();
338    let task = if let Some(task) = task_manager.get_task(tid as u32) {
339        task
340    } else {
341        return -ESRCH;
342    };
343    if task.lock().pid != current_task().lock().pid {
344        return -EINVAL;
345    }
346    task_manager.send_signal(task, sig as usize);
347    0
348}
349
350/// 向线程组 tgid 中线程 ID 为 tid 的线程发送信号 sig。
351/// # 参数:
352/// * `tgid` - 目标线程组的 ID
353/// * `tid` - 目标线程的 ID
354/// * `sig` - 要发送的信号编号
355/// # 返回值:
356/// * 成功时返回 0
357/// * 失败时返回负的错误码
358pub fn tgkill(tgid: c_int, tid: c_int, sig: c_int) -> c_int {
359    if sig < 0 || sig as usize >= NSIG {
360        return -EINVAL;
361    }
362    let task_manager = TASK_MANAGER.lock();
363    let task = if let Some(task) = task_manager.get_task(tid as u32) {
364        task
365    } else {
366        return -ESRCH;
367    };
368    if task.lock().pid != tgid as u32 {
369        return -EINVAL;
370    }
371    task_manager.send_signal(task, sig as usize);
372    0
373}
374
375/// 在任务中等待指定信号的到来
376/// # 参数
377/// * `task` - 任务引用
378/// * `signal` - 要等待的信号集合
379/// * `timeout` - 可选的超时时间
380/// # 返回值
381/// * 成功时返回收到的信号编号及其信息
382/// * 失败时返回负的错误码
383fn wait_for_signal(
384    task: SharedTask,
385    signal: SignalFlags,
386    timeout: Option<TimeSpec>,
387) -> Result<(usize, SigInfoT), i32> {
388    let mut t = task.lock();
389    if let Some(timeout) = timeout {
390        if timeout.tv_sec < 0 || timeout.tv_nsec < 0 || timeout.tv_nsec >= 1_000_000_000 {
391            return Err(-EINVAL);
392        }
393        if timeout.tv_sec == 0 && timeout.tv_nsec == 0 {
394            // 轮询, 不阻塞
395            if t.pending.has_deliverable_signal(signal)
396                || t.shared_pending.lock().has_deliverable_signal(signal)
397            {
398                let flag = t
399                    .pending
400                    .first_deliverable_signal(signal)
401                    .or_else(|| t.shared_pending.lock().first_deliverable_signal(signal))
402                    .unwrap();
403                let sig_num = flag.to_signal_number();
404                t.pending.signals.remove(flag);
405                return Ok((sig_num, create_siginfo_for_signal(flag)));
406            } else {
407                Err(-EAGAIN)
408            }
409        } else {
410            // 带超时的阻塞等待
411            let start = TimeSpec::now();
412            while !t.pending.has_deliverable_signal(signal)
413                && !t.shared_pending.lock().has_deliverable_signal(signal)
414            {
415                let now = TimeSpec::now();
416                if now - start > timeout {
417                    return Err(-EAGAIN); // 超时返回
418                }
419                TIMER_QUEUE
420                    .lock()
421                    .push(timeout.into_freq(clock_freq()), task.clone());
422                sleep_task_with_guard_and_block(&mut t, task.clone(), true);
423                drop(t);
424                yield_task();
425                t = task.lock();
426            }
427            TIMER_QUEUE.lock().remove_task(&task);
428            let flag = t
429                .pending
430                .first_deliverable_signal(signal)
431                .or_else(|| t.shared_pending.lock().first_deliverable_signal(signal))
432                .unwrap();
433            let sig_num = flag.to_signal_number();
434            t.pending.signals.remove(flag);
435            return Ok((sig_num, create_siginfo_for_signal(flag)));
436        }
437    } else {
438        // 阻塞等待
439        while t
440            .pending
441            .first_target_signal(signal)
442            .or_else(|| t.shared_pending.lock().first_target_signal(signal))
443            .is_none()
444        {
445            sleep_task_with_guard_and_block(&mut t, task.clone(), true);
446            drop(t);
447            yield_task();
448            t = task.lock();
449        }
450        let flag = t
451            .pending
452            .first_target_signal(signal)
453            .or_else(|| t.shared_pending.lock().first_target_signal(signal))
454            .unwrap();
455        let sig_num = flag.to_signal_number();
456        t.pending.signals.remove(flag);
457        return Ok((sig_num, create_siginfo_for_signal(flag)));
458    }
459}