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