1use core::sync::atomic::{AtomicU64, Ordering};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12#[repr(u32)]
13pub enum Signal {
14 SIGHUP = 1,
16 SIGINT = 2,
18 SIGQUIT = 3,
20 SIGILL = 4,
22 SIGTRAP = 5,
24 SIGABRT = 6,
26 SIGBUS = 7,
28 SIGFPE = 8,
30 SIGKILL = 9,
32 SIGUSR1 = 10,
34 SIGSEGV = 11,
36 SIGUSR2 = 12,
38 SIGPIPE = 13,
40 SIGALRM = 14,
42 SIGTERM = 15,
44 SIGCHLD = 17,
46 SIGCONT = 18,
48 SIGSTOP = 19,
50 SIGTSTP = 20,
52 SIGTTIN = 21,
54 SIGTTOU = 22,
56 SIGURG = 23,
58 SIGXCPU = 24,
60 SIGXFSZ = 25,
62 SIGVTALRM = 26,
64 SIGPROF = 27,
66 SIGWINCH = 28,
68 SIGIO = 29,
70 SIGPWR = 30,
72 SIGSYS = 31,
74}
75
76impl Signal {
77 pub fn from_u32(num: u32) -> Option<Self> {
79 match num {
80 1 => Some(Signal::SIGHUP),
81 2 => Some(Signal::SIGINT),
82 3 => Some(Signal::SIGQUIT),
83 4 => Some(Signal::SIGILL),
84 5 => Some(Signal::SIGTRAP),
85 6 => Some(Signal::SIGABRT),
86 7 => Some(Signal::SIGBUS),
87 8 => Some(Signal::SIGFPE),
88 9 => Some(Signal::SIGKILL),
89 10 => Some(Signal::SIGUSR1),
90 11 => Some(Signal::SIGSEGV),
91 12 => Some(Signal::SIGUSR2),
92 13 => Some(Signal::SIGPIPE),
93 14 => Some(Signal::SIGALRM),
94 15 => Some(Signal::SIGTERM),
95 17 => Some(Signal::SIGCHLD),
96 18 => Some(Signal::SIGCONT),
97 19 => Some(Signal::SIGSTOP),
98 20 => Some(Signal::SIGTSTP),
99 21 => Some(Signal::SIGTTIN),
100 22 => Some(Signal::SIGTTOU),
101 23 => Some(Signal::SIGURG),
102 24 => Some(Signal::SIGXCPU),
103 25 => Some(Signal::SIGXFSZ),
104 26 => Some(Signal::SIGVTALRM),
105 27 => Some(Signal::SIGPROF),
106 28 => Some(Signal::SIGWINCH),
107 29 => Some(Signal::SIGIO),
108 30 => Some(Signal::SIGPWR),
109 31 => Some(Signal::SIGSYS),
110 _ => None,
111 }
112 }
113
114 pub fn as_u32(self) -> u32 {
116 self as u32
117 }
118
119 pub fn is_uncatchable(self) -> bool {
121 matches!(self, Signal::SIGKILL | Signal::SIGSTOP)
122 }
123
124 pub fn bit(self) -> u64 {
126 1u64 << (self.as_u32() - 1)
127 }
128}
129
130pub const SIGNAL_MASK_SIZE: usize = 8; pub const SIGNAL_MAX: u32 = 64;
133
134pub const SIG_BLOCK: i32 = 0;
136pub const SIG_UNBLOCK: i32 = 1;
137pub const SIG_SETMASK: i32 = 2;
138
139#[derive(Debug)]
143pub struct SignalSet {
144 mask: AtomicU64,
145}
146
147impl Clone for SignalSet {
148 fn clone(&self) -> Self {
150 Self::from_mask(self.get_mask())
151 }
152}
153
154impl SignalSet {
155 pub const fn new() -> Self {
157 Self {
158 mask: AtomicU64::new(0),
159 }
160 }
161
162 pub const fn from_mask(mask: u64) -> Self {
164 Self {
165 mask: AtomicU64::new(mask),
166 }
167 }
168
169 pub fn add(&self, signal: Signal) {
171 let bit = signal.bit();
172 self.mask.fetch_or(bit, Ordering::Release);
173 }
174
175 pub fn remove(&self, signal: Signal) {
177 let bit = !signal.bit();
178 self.mask.fetch_and(bit, Ordering::AcqRel);
179 }
180
181 pub fn contains(&self, signal: Signal) -> bool {
183 let bit = signal.bit();
184 (self.mask.load(Ordering::Acquire) & bit) != 0
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.mask.load(Ordering::Acquire) == 0
190 }
191
192 pub fn get_mask(&self) -> u64 {
194 self.mask.load(Ordering::Acquire)
195 }
196
197 pub fn set_mask(&self, mask: u64) {
199 self.mask.store(mask, Ordering::Release);
200 }
201
202 pub fn clear(&self) {
204 self.mask.store(0, Ordering::Release);
205 }
206
207 pub fn next_pending(&self) -> Option<Signal> {
209 let pending = self.mask.load(Ordering::Acquire);
210 if pending == 0 {
211 return None;
212 }
213 let signal_num = pending.trailing_zeros() + 1;
214 Signal::from_u32(signal_num)
215 }
216
217 pub fn unblocked(&self, blocked: &SignalSet) -> u64 {
219 let pending = self.mask.load(Ordering::Acquire);
220 let blocked_mask = blocked.mask.load(Ordering::Acquire);
221 pending & !blocked_mask
222 }
223
224 pub fn consume_one_unblocked(&self, blocked: &SignalSet) -> Option<Signal> {
226 loop {
227 let pending = self.mask.load(Ordering::Acquire);
228 let blocked_mask = blocked.mask.load(Ordering::Acquire);
229 let unblocked = pending & !blocked_mask;
230 if unblocked == 0 {
231 return None;
232 }
233 let lowest_bit = unblocked & unblocked.wrapping_neg();
234 let new_pending = pending & !lowest_bit;
235 match self.mask.compare_exchange_weak(
236 pending,
237 new_pending,
238 Ordering::AcqRel,
239 Ordering::Acquire,
240 ) {
241 Ok(_) => {
242 let signal_num = lowest_bit.trailing_zeros() + 1;
243 return Signal::from_u32(signal_num);
244 }
245 Err(_) => continue,
246 }
247 }
248 }
249
250 pub fn peek_one_unblocked(&self, blocked: &SignalSet) -> Option<Signal> {
252 let pending = self.mask.load(Ordering::Acquire);
253 let blocked_mask = blocked.mask.load(Ordering::Acquire);
254 let unblocked = pending & !blocked_mask;
255 if unblocked == 0 {
256 return None;
257 }
258 let signal_num = unblocked.trailing_zeros() + 1;
259 Signal::from_u32(signal_num)
260 }
261
262 pub fn try_consume(&self, signal: Signal) -> bool {
264 let bit = signal.bit();
265 loop {
266 let pending = self.mask.load(Ordering::Acquire);
267 if (pending & bit) == 0 {
268 return false;
269 }
270 let new_pending = pending & !bit;
271 match self.mask.compare_exchange_weak(
272 pending,
273 new_pending,
274 Ordering::AcqRel,
275 Ordering::Acquire,
276 ) {
277 Ok(_) => return true,
278 Err(_) => continue,
279 }
280 }
281 }
282}
283
284pub const SA_NOCLDSTOP: u32 = 1 << 0;
286pub const SA_NOCLDWAIT: u32 = 1 << 1;
287pub const SA_SIGINFO: u32 = 1 << 2;
288pub const SA_RESTORER: u32 = 1 << 3;
289pub const SA_ONSTACK: u32 = 1 << 4;
290pub const SA_RESTART: u32 = 1 << 5;
291pub const SA_NODEFER: u32 = 1 << 6;
292pub const SA_RESETHAND: u32 = 1 << 7;
293
294pub const SIG_DFL: u64 = 0;
295pub const SIG_IGN: u64 = 1;
296
297#[derive(Debug, Clone, Copy)]
298#[repr(C)]
299pub struct SigActionData {
300 pub handler: u64,
301 pub flags: u64,
302 pub restorer: u64,
303 pub mask: u64,
304}
305
306impl SigActionData {
307 pub const fn default() -> Self {
309 Self {
310 handler: SIG_DFL,
311 flags: 0,
312 restorer: 0,
313 mask: 0,
314 }
315 }
316
317 pub fn is_default(&self) -> bool {
319 self.handler == SIG_DFL
320 }
321 pub fn is_ignore(&self) -> bool {
323 self.handler == SIG_IGN
324 }
325 pub fn is_user_handler(&self) -> bool {
327 self.handler > 1
328 }
329}
330
331impl Default for SigActionData {
332 fn default() -> Self {
334 Self::default()
335 }
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq)]
339pub enum DefaultAction {
340 Term,
341 Core,
342 Stop,
343 Cont,
344 Ign,
345}
346
347impl Signal {
348 pub fn default_action(self) -> DefaultAction {
350 match self {
351 Signal::SIGHUP
352 | Signal::SIGINT
353 | Signal::SIGPIPE
354 | Signal::SIGALRM
355 | Signal::SIGTERM
356 | Signal::SIGUSR1
357 | Signal::SIGUSR2
358 | Signal::SIGPROF
359 | Signal::SIGVTALRM
360 | Signal::SIGIO
361 | Signal::SIGPWR
362 | Signal::SIGSYS => DefaultAction::Term,
363
364 Signal::SIGQUIT
365 | Signal::SIGILL
366 | Signal::SIGABRT
367 | Signal::SIGFPE
368 | Signal::SIGSEGV
369 | Signal::SIGBUS
370 | Signal::SIGTRAP
371 | Signal::SIGXCPU
372 | Signal::SIGXFSZ => DefaultAction::Core,
373
374 Signal::SIGSTOP | Signal::SIGTSTP | Signal::SIGTTIN | Signal::SIGTTOU => {
375 DefaultAction::Stop
376 }
377
378 Signal::SIGCONT => DefaultAction::Cont,
379
380 Signal::SIGCHLD | Signal::SIGURG | Signal::SIGWINCH => DefaultAction::Ign,
381
382 Signal::SIGKILL => DefaultAction::Term,
383 }
384 }
385}
386
387pub const SIGNAL_FRAME_MAGIC: u64 = 0x5354_5239_5349_4700;
388
389#[derive(Debug, Clone, Copy)]
390#[repr(C)]
391pub struct SignalFrame {
392 pub restorer: u64,
393 pub signo: u64,
394 pub saved_mask: u64,
395 pub rip: u64,
396 pub rsp: u64,
397 pub rflags: u64,
398 pub rax: u64,
399 pub rcx: u64,
400 pub rdx: u64,
401 pub rbx: u64,
402 pub rbp: u64,
403 pub rsi: u64,
404 pub rdi: u64,
405 pub r8: u64,
406 pub r9: u64,
407 pub r10: u64,
408 pub r11: u64,
409 pub r12: u64,
410 pub r13: u64,
411 pub r14: u64,
412 pub r15: u64,
413 pub magic: u64,
414}
415
416#[derive(Clone, Copy, PartialEq, Eq)]
417enum SignalDeliveryMode {
418 Normal,
419 InterruptReturn,
420}
421
422pub static SIGNAL_IRQ_DEFERRED_COUNT: AtomicU64 = AtomicU64::new(0);
426
427fn deliver_pending_signal_inner(
428 frame: &mut crate::syscall::SyscallFrame,
429 mode: SignalDeliveryMode,
430) -> bool {
431 let task = match crate::process::current_task_clone() {
432 Some(t) => t,
433 None => return false,
434 };
435
436 if task.is_kernel() {
437 return false;
438 }
439
440 if mode == SignalDeliveryMode::InterruptReturn
441 && task.irq_signal_delivery_blocked.load(Ordering::Acquire)
442 {
443 return false;
444 }
445
446 if mode == SignalDeliveryMode::Normal {
447 task.irq_signal_delivery_blocked
448 .store(false, Ordering::Release);
449 }
450
451 let signal = match task
456 .pending_signals
457 .peek_one_unblocked(&task.blocked_signals)
458 {
459 Some(s) => s,
460 None => return false,
461 };
462
463 let action = unsafe {
464 let actions = &*task.process.signal_actions.get();
465 actions[signal.as_u32() as usize]
466 };
467
468 if action.is_ignore() {
469 debug_assert!(
470 task.pending_signals.try_consume(signal),
471 "signal vanished between peek and consume (ignore path)"
472 );
473 return true;
474 }
475
476 if action.is_default() {
477 match signal.default_action() {
478 DefaultAction::Ign | DefaultAction::Cont => {
479 debug_assert!(
480 task.pending_signals.try_consume(signal),
481 "signal vanished between peek and consume (ign/cont path)"
482 );
483 return true;
484 }
485 DefaultAction::Stop => {
486 if mode == SignalDeliveryMode::InterruptReturn {
487 task.irq_signal_delivery_blocked
490 .store(true, Ordering::Release);
491 SIGNAL_IRQ_DEFERRED_COUNT.fetch_add(1, Ordering::Relaxed);
492 return false;
493 }
494 debug_assert!(
495 task.pending_signals.try_consume(signal),
496 "signal vanished between peek and consume (stop path)"
497 );
498 return true;
499 }
500 DefaultAction::Term | DefaultAction::Core => {
501 if mode == SignalDeliveryMode::InterruptReturn {
502 task.irq_signal_delivery_blocked
505 .store(true, Ordering::Release);
506 SIGNAL_IRQ_DEFERRED_COUNT.fetch_add(1, Ordering::Relaxed);
507 return false;
508 }
509 if !task.pending_signals.try_consume(signal) {
510 return false;
511 }
512 log::info!(
513 "[signal] killing pid {} on SIG{}",
514 task.pid,
515 signal.as_u32()
516 );
517 crate::process::kill_task(task.id);
518 return true;
519 }
520 }
521 }
522
523 let handler = action.handler;
524 let restorer = action.restorer;
525 let sig_mask = action.mask;
526 let flags = action.flags;
527
528 if restorer == 0 {
529 if mode == SignalDeliveryMode::InterruptReturn {
530 task.irq_signal_delivery_blocked
532 .store(true, Ordering::Release);
533 SIGNAL_IRQ_DEFERRED_COUNT.fetch_add(1, Ordering::Relaxed);
534 return false;
535 }
536 if !task.pending_signals.try_consume(signal) {
537 return false;
538 }
539 log::warn!("[signal] no restorer for SIG{}, killing", signal.as_u32());
540 crate::process::kill_task(task.id);
541 return true;
542 }
543
544 if !task.pending_signals.try_consume(signal) {
545 return false;
546 }
547
548 let user_rsp = frame.iret_rsp;
549 let frame_size = core::mem::size_of::<SignalFrame>() as u64;
550 let new_rsp = ((user_rsp - frame_size) & !0xF) - 8;
551
552 let sig_frame = SignalFrame {
553 restorer,
554 signo: signal.as_u32() as u64,
555 saved_mask: task.blocked_signals.get_mask(),
556 rip: frame.iret_rip,
557 rsp: frame.iret_rsp,
558 rflags: frame.iret_rflags,
559 rax: frame.rax,
560 rcx: frame.rcx,
561 rdx: frame.rdx,
562 rbx: frame.rbx,
563 rbp: frame.rbp,
564 rsi: frame.rsi,
565 rdi: frame.rdi,
566 r8: frame.r8,
567 r9: frame.r9,
568 r10: frame.r10,
569 r11: frame.r11,
570 r12: frame.r12,
571 r13: frame.r13,
572 r14: frame.r14,
573 r15: frame.r15,
574 magic: SIGNAL_FRAME_MAGIC,
575 };
576
577 let bytes: &[u8] = unsafe {
578 core::slice::from_raw_parts(
579 &sig_frame as *const SignalFrame as *const u8,
580 core::mem::size_of::<SignalFrame>(),
581 )
582 };
583
584 match crate::memory::UserSliceWrite::new(new_rsp, bytes.len()) {
585 Ok(slice) => {
586 slice.copy_from(bytes);
587 }
588 Err(_) => {
589 if mode == SignalDeliveryMode::InterruptReturn {
590 task.irq_signal_delivery_blocked
591 .store(true, Ordering::Release);
592 task.pending_signals.add(signal);
593 return false;
594 }
595 log::warn!("[signal] fault writing signal frame, killing");
596 crate::process::kill_task(task.id);
597 return true;
598 }
599 }
600
601 let mut new_mask = task.blocked_signals.get_mask() | sig_mask;
603 if flags & (SA_NODEFER as u64) == 0 {
604 new_mask |= signal.bit();
605 }
606 task.blocked_signals.set_mask(new_mask);
607
608 if flags & (SA_RESETHAND as u64) != 0 {
610 unsafe {
611 let actions = &mut *task.process.signal_actions.get();
612 actions[signal.as_u32() as usize] = SigActionData::default();
613 }
614 }
615
616 frame.iret_rip = handler;
617 frame.iret_rsp = new_rsp;
618 frame.rdi = signal.as_u32() as u64;
619 frame.rsi = 0;
620 frame.rdx = 0;
621
622 true
623}
624
625pub fn deliver_pending_signal(frame: &mut crate::syscall::SyscallFrame) -> bool {
627 deliver_pending_signal_inner(frame, SignalDeliveryMode::Normal)
628}
629
630pub fn deliver_pending_signal_on_interrupt_return(
640 frame: &mut crate::syscall::SyscallFrame,
641) -> bool {
642 deliver_pending_signal_inner(frame, SignalDeliveryMode::InterruptReturn)
643}
644
645#[derive(Debug, Clone, Copy, Default)]
647#[repr(C)]
648pub struct SigStack {
649 pub ss_sp: u64,
651 pub ss_flags: i32,
653 pub ss_size: usize,
655}
656
657pub fn send_signal(
669 target: crate::process::TaskId,
670 signal: Signal,
671) -> Result<(), crate::syscall::error::SyscallError> {
672 use crate::{process::get_task_by_id, syscall::error::SyscallError};
673
674 if signal.is_uncatchable() {
676 }
678
679 let task = get_task_by_id(target).ok_or(SyscallError::InvalidArgument)?;
680
681 let pending = &task.pending_signals;
684 pending.add(signal);
685
686 {
691 let state = task.get_state();
692 if state == crate::process::TaskState::Blocked {
693 let blocked = &task.blocked_signals;
694 if !blocked.contains(signal) {
695 crate::process::wake_task(target);
697 }
698 }
699 }
700
701 Ok(())
702}
703
704pub fn has_pending_signals() -> bool {
708 use crate::process::current_task_clone;
709
710 if let Some(task) = current_task_clone() {
711 let pending = &task.pending_signals;
712 let blocked = &task.blocked_signals;
713 pending.unblocked(blocked) != 0
714 } else {
715 false
716 }
717}
718
719pub fn consume_next_signal() -> Option<Signal> {
723 use crate::process::current_task_clone;
724
725 if let Some(task) = current_task_clone() {
726 task.pending_signals
727 .consume_one_unblocked(&task.blocked_signals)
728 } else {
729 None
730 }
731}