1 use core::sync::atomic::compiler_fence;
2
3 use alloc::sync::Arc;
4 use log::warn;
5 use system_error::SystemError;
6
7 use crate::{
8 arch::ipc::signal::{SigCode, SigFlags, SigSet, Signal},
9 ipc::signal_types::SigactionType,
10 libs::spinlock::SpinLockGuard,
11 process::{pid::PidType, Pid, ProcessControlBlock, ProcessFlags, ProcessManager},
12 };
13
14 use super::signal_types::{
15 SaHandlerType, SigInfo, SigType, Sigaction, SignalStruct, SIG_KERNEL_STOP_MASK,
16 };
17
18 impl Signal {
signal_pending_state( interruptible: bool, task_wake_kill: bool, pcb: &Arc<ProcessControlBlock>, ) -> bool19 pub fn signal_pending_state(
20 interruptible: bool,
21 task_wake_kill: bool,
22 pcb: &Arc<ProcessControlBlock>,
23 ) -> bool {
24 if !interruptible && !task_wake_kill {
25 return false;
26 }
27
28 if !pcb.has_pending_signal() {
29 return false;
30 }
31
32 return interruptible || Self::fatal_signal_pending(pcb);
33 }
34
35 /// 判断当前进程是否收到了SIGKILL信号
fatal_signal_pending(pcb: &Arc<ProcessControlBlock>) -> bool36 pub fn fatal_signal_pending(pcb: &Arc<ProcessControlBlock>) -> bool {
37 let guard = pcb.sig_info_irqsave();
38 if guard
39 .sig_pending()
40 .signal()
41 .contains(Signal::SIGKILL.into())
42 {
43 return true;
44 }
45
46 return false;
47 }
48 /// 向目标进程发送信号
49 ///
50 /// ## 参数
51 ///
52 /// - `sig` 要发送的信号
53 /// - `info` 要发送的信息
54 /// - `pid` 进程id(目前只支持pid>0)
send_signal_info( &self, info: Option<&mut SigInfo>, pid: Pid, ) -> Result<i32, SystemError>55 pub fn send_signal_info(
56 &self,
57 info: Option<&mut SigInfo>,
58 pid: Pid,
59 ) -> Result<i32, SystemError> {
60 // TODO:暂时不支持特殊的信号操作,待引入进程组后补充
61 // 如果 pid 大于 0,那么会发送信号给 pid 指定的进程
62 // 如果 pid 等于 0,那么会发送信号给与调用进程同组的每个进程,包括调用进程自身
63 // 如果 pid 小于 -1,那么会向组 ID 等于该 pid 绝对值的进程组内所有下属进程发送信号。向一个进程组的所有进程发送信号在 shell 作业控制中有特殊有途
64 // 如果 pid 等于 -1,那么信号的发送范围是:调用进程有权将信号发往的每个目标进程,除去 init(进程 ID 为 1)和调用进程自身。如果特权级进程发起这一调用,那么会发送信号给系统中的所有进程,上述两个进程除外。显而易见,有时也将这种信号发送方式称之为广播信号
65 // 如果并无进程与指定的 pid 相匹配,那么 kill() 调用失败,同时将 errno 置为 ESRCH(“查无此进程”)
66 if pid.lt(&Pid::from(0)) {
67 warn!("Kill operation not support: pid={:?}", pid);
68 return Err(SystemError::ENOSYS);
69 }
70 compiler_fence(core::sync::atomic::Ordering::SeqCst);
71 // 检查sig是否符合要求,如果不符合要求,则退出。
72 if !self.is_valid() {
73 return Err(SystemError::EINVAL);
74 }
75 let mut retval = Err(SystemError::ESRCH);
76 let pcb = ProcessManager::find(pid);
77
78 if pcb.is_none() {
79 warn!("No such process.");
80 return retval;
81 }
82
83 let pcb = pcb.unwrap();
84 // println!("Target pcb = {:?}", pcb.as_ref().unwrap());
85 compiler_fence(core::sync::atomic::Ordering::SeqCst);
86 // 发送信号
87 retval = self.send_signal(info, pcb.clone(), PidType::PID);
88
89 compiler_fence(core::sync::atomic::Ordering::SeqCst);
90 return retval;
91 }
92
93 /// @brief 判断是否需要强制发送信号,然后发送信号
94 /// 进入函数后加锁
95 ///
96 /// @return SystemError 错误码
send_signal( &self, info: Option<&mut SigInfo>, pcb: Arc<ProcessControlBlock>, pt: PidType, ) -> Result<i32, SystemError>97 fn send_signal(
98 &self,
99 info: Option<&mut SigInfo>,
100 pcb: Arc<ProcessControlBlock>,
101 pt: PidType,
102 ) -> Result<i32, SystemError> {
103 // 是否强制发送信号
104 let mut force_send = false;
105 // signal的信息为空
106
107 if let Some(ref siginfo) = info {
108 force_send = matches!(siginfo.sig_code(), SigCode::Kernel);
109 } else {
110 // todo: 判断signal是否来自于一个祖先进程的namespace,如果是,则强制发送信号
111 //详见 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c?r=&mo=32170&fi=1220#1226
112 }
113
114 if !self.prepare_sianal(pcb.clone(), force_send) {
115 return Err(SystemError::EINVAL);
116 }
117 // debug!("force send={}", force_send);
118 let pcb_info = pcb.sig_info_irqsave();
119 let pending = if matches!(pt, PidType::PID) {
120 pcb_info.sig_shared_pending()
121 } else {
122 pcb_info.sig_pending()
123 };
124 compiler_fence(core::sync::atomic::Ordering::SeqCst);
125 // 如果是kill或者目标pcb是内核线程,则无需获取sigqueue,直接发送信号即可
126 if matches!(self, Signal::SIGKILL) || pcb.flags().contains(ProcessFlags::KTHREAD) {
127 //避免死锁
128 drop(pcb_info);
129 self.complete_signal(pcb.clone(), pt);
130 }
131 // 如果不是实时信号的话,同一时刻信号队列里只会有一个待处理的信号,如果重复接收就不做处理
132 else if !self.is_rt_signal() && pending.queue().find(*self).0.is_some() {
133 return Ok(0);
134 } else {
135 // TODO signalfd_notify 完善 signalfd 机制
136 // 如果是其他信号,则加入到sigqueue内,然后complete_signal
137 let new_sig_info = match info {
138 Some(siginfo) => {
139 // 已经显式指定了siginfo,则直接使用它。
140 *siginfo
141 }
142 None => {
143 // 不需要显示指定siginfo,因此设置为默认值
144 SigInfo::new(
145 *self,
146 0,
147 SigCode::User,
148 SigType::Kill(ProcessManager::current_pcb().pid()),
149 )
150 }
151 };
152 drop(pcb_info);
153 pcb.sig_info_mut()
154 .sig_pending_mut()
155 .queue_mut()
156 .q
157 .push(new_sig_info);
158
159 // if pt == PidType::PGID || pt == PidType::SID {}
160 self.complete_signal(pcb.clone(), pt);
161 }
162 compiler_fence(core::sync::atomic::Ordering::SeqCst);
163 return Ok(0);
164 }
165
166 /// @brief 将信号添加到目标进程的sig_pending。在引入进程组后,本函数还将负责把信号传递给整个进程组。
167 ///
168 /// @param sig 信号
169 /// @param pcb 目标pcb
170 /// @param pt siginfo结构体中,pid字段代表的含义
171 #[allow(clippy::if_same_then_else)]
complete_signal(&self, pcb: Arc<ProcessControlBlock>, pt: PidType)172 fn complete_signal(&self, pcb: Arc<ProcessControlBlock>, pt: PidType) {
173 // debug!("complete_signal");
174
175 compiler_fence(core::sync::atomic::Ordering::SeqCst);
176 // ===== 寻找需要wakeup的目标进程 =====
177 // 备注:由于当前没有进程组的概念,每个进程只有1个对应的线程,因此不需要通知进程组内的每个进程。
178 // todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。
179
180 // let _signal = pcb.sig_struct();
181
182 let target_pcb: Option<Arc<ProcessControlBlock>>;
183
184 // 判断目标进程是否想接收这个信号
185 if self.wants_signal(pcb.clone()) {
186 // todo: 将信号产生的消息通知到正在监听这个信号的进程(引入signalfd之后,在这里调用signalfd_notify)
187 // 将这个信号加到目标进程的sig_pending中
188 pcb.sig_info_mut()
189 .sig_pending_mut()
190 .signal_mut()
191 .insert((*self).into());
192 target_pcb = Some(pcb.clone());
193 } else if pt == PidType::PID {
194 /*
195 * There is just one thread and it does not need to be woken.
196 * It will dequeue unblocked signals before it runs again.
197 */
198 return;
199 } else {
200 /*
201 * Otherwise try to find a suitable thread.
202 * 由于目前每个进程只有1个线程,因此当前情况可以返回。信号队列的dequeue操作不需要考虑同步阻塞的问题。
203 */
204 return;
205 }
206
207 // TODO:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。
208 compiler_fence(core::sync::atomic::Ordering::SeqCst);
209 // TODO: 到这里,信号已经被放置在共享的pending队列中,我们在这里把目标进程唤醒。
210 if let Some(target_pcb) = target_pcb {
211 let guard = target_pcb.sig_struct();
212 signal_wake_up(target_pcb.clone(), guard, *self == Signal::SIGKILL);
213 }
214 }
215
216 /// @brief 本函数用于检测指定的进程是否想要接收SIG这个信号。
217 /// 当我们对于进程组中的所有进程都运行了这个检查之后,我们将可以找到组内愿意接收信号的进程。
218 /// 这么做是为了防止我们把信号发送给了一个正在或已经退出的进程,或者是不响应该信号的进程。
219 #[inline]
wants_signal(&self, pcb: Arc<ProcessControlBlock>) -> bool220 fn wants_signal(&self, pcb: Arc<ProcessControlBlock>) -> bool {
221 // 如果改进程屏蔽了这个signal,则不能接收
222 if pcb.sig_info_irqsave().sig_block().contains((*self).into()) {
223 return false;
224 }
225
226 // 如果进程正在退出,则不能接收信号
227 if pcb.flags().contains(ProcessFlags::EXITING) {
228 return false;
229 }
230
231 if *self == Signal::SIGKILL {
232 return true;
233 }
234 let state = pcb.sched_info().inner_lock_read_irqsave().state();
235 if state.is_blocked() && (!state.is_blocked_interruptable()) {
236 return false;
237 }
238
239 // todo: 检查目标进程是否正在一个cpu上执行,如果是,则返回true,否则继续检查下一项
240
241 // 检查目标进程是否有信号正在等待处理,如果是,则返回false,否则返回true
242 return pcb.sig_info_irqsave().sig_pending().signal().bits() == 0;
243 }
244
245 /// @brief 判断signal的处理是否可能使得整个进程组退出
246 /// @return true 可能会导致退出(不一定)
247 #[allow(dead_code)]
248 #[inline]
sig_fatal(&self, pcb: Arc<ProcessControlBlock>) -> bool249 fn sig_fatal(&self, pcb: Arc<ProcessControlBlock>) -> bool {
250 let action = pcb.sig_struct().handlers[*self as usize - 1].action();
251 // 如果handler是空,采用默认函数,signal处理可能会导致进程退出。
252 match action {
253 SigactionType::SaHandler(handler) => handler.is_sig_default(),
254 SigactionType::SaSigaction(sigaction) => sigaction.is_none(),
255 }
256 // todo: 参照linux的sig_fatal实现完整功能
257 }
258
259 /// 检查信号是否能被发送,并且而且要处理 SIGCONT 和 STOP 信号
260 ///
261 /// ## 参数
262 ///
263 /// - `pcb` 要发送信号的目标pcb
264 ///
265 /// - `force` 是否强制发送(指走 fast path , 不加入 sigpending按顺序处理,直接进入 complete_signal)
266 ///
267 /// ## 返回值
268 ///
269 /// - `true` 能够发送信号
270 ///
271 /// - `false` 不能发送信号
prepare_sianal(&self, pcb: Arc<ProcessControlBlock>, _force: bool) -> bool272 fn prepare_sianal(&self, pcb: Arc<ProcessControlBlock>, _force: bool) -> bool {
273 let flush: SigSet;
274 if !(self.into_sigset() & SIG_KERNEL_STOP_MASK).is_empty() {
275 flush = Signal::SIGCONT.into_sigset();
276 pcb.sig_info_mut()
277 .sig_shared_pending_mut()
278 .flush_by_mask(&flush);
279 // TODO 对每个子线程 flush mask
280 } else if *self == Signal::SIGCONT {
281 flush = SIG_KERNEL_STOP_MASK;
282 assert!(!flush.is_empty());
283 pcb.sig_info_mut()
284 .sig_shared_pending_mut()
285 .flush_by_mask(&flush);
286 let _r = ProcessManager::wakeup_stop(&pcb);
287 // TODO 对每个子线程 flush mask
288 // 这里需要补充一段逻辑,详见https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/signal.c#952
289 }
290
291 // 一个被阻塞了的信号肯定是要被处理的
292 if pcb
293 .sig_info_irqsave()
294 .sig_block()
295 .contains(self.into_sigset())
296 {
297 return true;
298 }
299 return !pcb.sig_struct().handlers[*self as usize - 1].is_ignore();
300
301 //TODO 仿照 linux 中的prepare signal完善逻辑,linux 中还会根据例如当前进程状态(Existing)进行判断,现在的信号能否发出就只是根据 ignored 来判断
302 }
303 }
304
305 /// 因收到信号而唤醒进程
306 ///
307 /// ## 参数
308 ///
309 /// - `pcb` 要唤醒的进程pcb
310 /// - `_guard` 信号结构体锁守卫,来保证信号结构体已上锁
311 /// - `fatal` 表明这个信号是不是致命的(会导致进程退出)
312 #[inline]
signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStruct>, fatal: bool)313 fn signal_wake_up(pcb: Arc<ProcessControlBlock>, _guard: SpinLockGuard<SignalStruct>, fatal: bool) {
314 // 如果是 fatal 的话就唤醒 stop 和 block 的进程来响应,因为唤醒后就会终止
315 // 如果不是 fatal 的就只唤醒 stop 的进程来响应
316 // debug!("signal_wake_up");
317 // 如果目标进程已经在运行,则发起一个ipi,使得它陷入内核
318 let state = pcb.sched_info().inner_lock_read_irqsave().state();
319 let mut wakeup_ok = true;
320 if state.is_blocked_interruptable() {
321 ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
322 wakeup_ok = false;
323 warn!(
324 "Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
325 ProcessManager::current_pcb().pid(),
326 pcb.pid(),
327 e
328 );
329 });
330 } else if state.is_stopped() {
331 ProcessManager::wakeup_stop(&pcb).unwrap_or_else(|e| {
332 wakeup_ok = false;
333 warn!(
334 "Current pid: {:?}, signal_wake_up target {:?} error: {:?}",
335 ProcessManager::current_pcb().pid(),
336 pcb.pid(),
337 e
338 );
339 });
340 } else {
341 wakeup_ok = false;
342 }
343
344 if wakeup_ok {
345 ProcessManager::kick(&pcb);
346 } else if fatal {
347 let _r = ProcessManager::wakeup(&pcb).map(|_| {
348 ProcessManager::kick(&pcb);
349 });
350 }
351 }
352
353 /// @brief 当一个进程具有多个线程之后,在这里需要重新计算线程的flag中的TIF_SIGPENDING位
recalc_sigpending()354 fn recalc_sigpending() {
355 // todo:
356 }
357
358 /// @brief 刷新指定进程的sighand的sigaction,将满足条件的sigaction恢复为Default
359 /// 除非某个信号被设置为ignore且force_default为false,否则都不会将其恢复
360 ///
361 /// @param pcb 要被刷新的pcb
362 /// @param force_default 是否强制将sigaction恢复成默认状态
flush_signal_handlers(pcb: Arc<ProcessControlBlock>, force_default: bool)363 pub fn flush_signal_handlers(pcb: Arc<ProcessControlBlock>, force_default: bool) {
364 compiler_fence(core::sync::atomic::Ordering::SeqCst);
365 // debug!("hand=0x{:018x}", hand as *const sighand_struct as usize);
366 let actions = &mut pcb.sig_struct_irqsave().handlers;
367
368 for sigaction in actions.iter_mut() {
369 if force_default || !sigaction.is_ignore() {
370 sigaction.set_action(SigactionType::SaHandler(SaHandlerType::Default));
371 }
372 // 清除flags中,除了DFL和IGN以外的所有标志
373 sigaction.set_restorer(None);
374 sigaction.mask_mut().remove(SigSet::all());
375 compiler_fence(core::sync::atomic::Ordering::SeqCst);
376 }
377 compiler_fence(core::sync::atomic::Ordering::SeqCst);
378 }
379
do_sigaction( sig: Signal, act: Option<&mut Sigaction>, old_act: Option<&mut Sigaction>, ) -> Result<(), SystemError>380 pub(super) fn do_sigaction(
381 sig: Signal,
382 act: Option<&mut Sigaction>,
383 old_act: Option<&mut Sigaction>,
384 ) -> Result<(), SystemError> {
385 if sig == Signal::INVALID {
386 return Err(SystemError::EINVAL);
387 }
388 let pcb = ProcessManager::current_pcb();
389 // 指向当前信号的action的引用
390 let action: &mut Sigaction = &mut pcb.sig_struct().handlers[sig as usize - 1];
391
392 // 对比 MUSL 和 relibc , 暂时不设置这个标志位
393 // if action.flags().contains(SigFlags::SA_FLAG_IMMUTABLE) {
394 // return Err(SystemError::EINVAL);
395 // }
396
397 // 保存原有的 sigaction
398 let old_act: Option<&mut Sigaction> = {
399 if let Some(oa) = old_act {
400 *(oa) = *action;
401 Some(oa)
402 } else {
403 None
404 }
405 };
406 // 清除所有的脏的sa_flags位(也就是清除那些未使用的)
407 let act = {
408 if let Some(ac) = act {
409 *ac.flags_mut() &= SigFlags::SA_ALL;
410 Some(ac)
411 } else {
412 None
413 }
414 };
415
416 if let Some(act) = old_act {
417 *act.flags_mut() &= SigFlags::SA_ALL;
418 }
419
420 if let Some(ac) = act {
421 // 将act.sa_mask的SIGKILL SIGSTOP的屏蔽清除
422 ac.mask_mut()
423 .remove(<Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into());
424
425 // 将新的sigaction拷贝到进程的action中
426 *action = *ac;
427 /*
428 * 根据POSIX 3.3.1.3规定:
429 * 1.不管一个信号是否被阻塞,只要将其设置SIG_IGN,如果当前已经存在了正在pending的信号,那么就把这个信号忽略。
430 *
431 * 2.不管一个信号是否被阻塞,只要将其设置SIG_DFL,如果当前已经存在了正在pending的信号,
432 并且对这个信号的默认处理方式是忽略它,那么就会把pending的信号忽略。
433 */
434 if action.is_ignore() {
435 let mut mask: SigSet = SigSet::from_bits_truncate(0);
436 mask.insert(sig.into());
437 pcb.sig_info_mut().sig_pending_mut().flush_by_mask(&mask);
438 // todo: 当有了多个线程后,在这里进行操作,把每个线程的sigqueue都进行刷新
439 }
440 }
441 return Ok(());
442 }
443
444 /// 设置当前进程的屏蔽信号 (sig_block),待引入 [sigprocmask](https://man7.org/linux/man-pages/man2/sigprocmask.2.html) 系统调用后要删除这个散装函数
445 ///
446 /// ## 参数
447 ///
448 /// - `new_set` 新的屏蔽信号bitmap的值
set_current_sig_blocked(new_set: &mut SigSet)449 pub fn set_current_sig_blocked(new_set: &mut SigSet) {
450 let to_remove: SigSet =
451 <Signal as Into<SigSet>>::into(Signal::SIGKILL) | Signal::SIGSTOP.into();
452 new_set.remove(to_remove);
453 //TODO 把这个散装函数用 sigsetops 替换掉
454 let pcb = ProcessManager::current_pcb();
455
456 /*
457 如果当前pcb的sig_blocked和新的相等,那么就不用改变它。
458 请注意,一个进程的sig_blocked字段不能被其他进程修改!
459 */
460 if pcb.sig_info_irqsave().sig_block().eq(new_set) {
461 return;
462 }
463
464 let guard = pcb.sig_struct_irqsave();
465 // todo: 当一个进程有多个线程后,在这里需要设置每个线程的block字段,并且 retarget_shared_pending(虽然我还没搞明白linux这部分是干啥的)
466
467 // 设置当前进程的sig blocked
468 *pcb.sig_info_mut().sig_block_mut() = *new_set;
469 recalc_sigpending();
470 drop(guard);
471 }
472