kernel/abi/linux/riscv64/
signal.rs1use crate::abi::linux::riscv64::LinuxRiscv64Abi;
7use crate::arch::Trapframe;
8use crate::ipc::event::{Event, EventContent, ProcessControlType};
9use crate::task::mytask;
10use alloc::collections::BTreeMap;
11
12#[repr(u32)]
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
15pub enum LinuxSignal {
16 SIGHUP = 1,
17 SIGINT = 2,
18 SIGQUIT = 3,
19 SIGILL = 4,
20 SIGTRAP = 5,
21 SIGABRT = 6,
22 SIGBUS = 7,
23 SIGFPE = 8,
24 SIGKILL = 9,
25 SIGUSR1 = 10,
26 SIGSEGV = 11,
27 SIGUSR2 = 12,
28 SIGPIPE = 13,
29 SIGALRM = 14,
30 SIGTERM = 15,
31 SIGSTKFLT = 16,
32 SIGCHLD = 17,
33 SIGCONT = 18,
34 SIGSTOP = 19,
35 SIGTSTP = 20,
36 SIGTTIN = 21,
37 SIGTTOU = 22,
38 SIGURG = 23,
39 SIGXCPU = 24,
40 SIGXFSZ = 25,
41 SIGVTALRM = 26,
42 SIGPROF = 27,
43 SIGWINCH = 28,
44 SIGIO = 29,
45 SIGPWR = 30,
46 SIGSYS = 31,
47}
48
49impl LinuxSignal {
50 pub fn from_u32(signal: u32) -> Option<Self> {
52 match signal {
53 1 => Some(Self::SIGHUP),
54 2 => Some(Self::SIGINT),
55 3 => Some(Self::SIGQUIT),
56 4 => Some(Self::SIGILL),
57 5 => Some(Self::SIGTRAP),
58 6 => Some(Self::SIGABRT),
59 7 => Some(Self::SIGBUS),
60 8 => Some(Self::SIGFPE),
61 9 => Some(Self::SIGKILL),
62 10 => Some(Self::SIGUSR1),
63 11 => Some(Self::SIGSEGV),
64 12 => Some(Self::SIGUSR2),
65 13 => Some(Self::SIGPIPE),
66 14 => Some(Self::SIGALRM),
67 15 => Some(Self::SIGTERM),
68 16 => Some(Self::SIGSTKFLT),
69 17 => Some(Self::SIGCHLD),
70 18 => Some(Self::SIGCONT),
71 19 => Some(Self::SIGSTOP),
72 20 => Some(Self::SIGTSTP),
73 21 => Some(Self::SIGTTIN),
74 22 => Some(Self::SIGTTOU),
75 23 => Some(Self::SIGURG),
76 24 => Some(Self::SIGXCPU),
77 25 => Some(Self::SIGXFSZ),
78 26 => Some(Self::SIGVTALRM),
79 27 => Some(Self::SIGPROF),
80 28 => Some(Self::SIGWINCH),
81 29 => Some(Self::SIGIO),
82 30 => Some(Self::SIGPWR),
83 31 => Some(Self::SIGSYS),
84 _ => None,
85 }
86 }
87
88 pub fn default_action(&self) -> SignalAction {
90 match self {
91 Self::SIGKILL | Self::SIGSTOP => SignalAction::ForceTerminate,
92 Self::SIGCHLD | Self::SIGURG | Self::SIGWINCH => SignalAction::Ignore,
93 Self::SIGCONT => SignalAction::Continue,
94 Self::SIGTSTP | Self::SIGTTIN | Self::SIGTTOU => SignalAction::Stop,
95 _ => SignalAction::Terminate,
96 }
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102pub enum SignalAction {
103 Terminate,
105 ForceTerminate,
107 Ignore,
109 Stop,
111 Continue,
113 Custom(usize), }
116
117#[derive(Debug, Clone, Copy, Default)]
119pub struct SignalMask {
120 mask: u64, }
122
123impl SignalMask {
124 pub fn new() -> Self {
125 Self { mask: 0 }
126 }
127
128 pub fn block_signal(&mut self, signal: LinuxSignal) {
129 self.mask |= 1u64 << (signal as u32 - 1);
130 }
131
132 pub fn unblock_signal(&mut self, signal: LinuxSignal) {
133 self.mask &= !(1u64 << (signal as u32 - 1));
134 }
135
136 pub fn is_blocked(&self, signal: LinuxSignal) -> bool {
137 (self.mask & (1u64 << (signal as u32 - 1))) != 0
138 }
139
140 pub fn raw(&self) -> u64 {
141 self.mask
142 }
143
144 pub fn set_raw(&mut self, mask: u64) {
145 self.mask = mask;
146 }
147}
148
149#[derive(Debug, Clone)]
151pub struct SignalState {
152 pub handlers: BTreeMap<LinuxSignal, SignalAction>,
154 pub blocked: SignalMask,
156 pub pending: SignalMask,
158}
159
160impl Default for SignalState {
161 fn default() -> Self {
162 let mut handlers = BTreeMap::new();
163 for signal_num in 1..=31 {
165 if let Some(signal) = LinuxSignal::from_u32(signal_num) {
166 handlers.insert(signal, signal.default_action());
167 }
168 }
169
170 Self {
171 handlers,
172 blocked: SignalMask::new(),
173 pending: SignalMask::new(),
174 }
175 }
176}
177
178impl SignalState {
179 pub fn new() -> Self {
180 Self::default()
181 }
182
183 pub fn set_handler(&mut self, signal: LinuxSignal, action: SignalAction) {
185 if signal != LinuxSignal::SIGKILL && signal != LinuxSignal::SIGSTOP {
187 self.handlers.insert(signal, action);
188 }
189 }
190
191 pub fn get_handler(&self, signal: LinuxSignal) -> SignalAction {
193 self.handlers
194 .get(&signal)
195 .copied()
196 .unwrap_or(signal.default_action())
197 }
198
199 pub fn add_pending(&mut self, signal: LinuxSignal) {
201 self.pending.block_signal(signal);
202 }
203
204 pub fn remove_pending(&mut self, signal: LinuxSignal) {
206 self.pending.unblock_signal(signal);
207 }
208
209 pub fn is_pending(&self, signal: LinuxSignal) -> bool {
211 self.pending.is_blocked(signal)
212 }
213
214 pub fn next_deliverable_signal(&self) -> Option<LinuxSignal> {
216 for signal_num in 1..=31 {
217 if let Some(signal) = LinuxSignal::from_u32(signal_num) {
218 if self.is_pending(signal) && !self.blocked.is_blocked(signal) {
219 return Some(signal);
220 }
221 }
222 }
223 None
224 }
225}
226
227pub fn sys_rt_sigaction(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
231 let task = mytask().unwrap();
232
233 let signum = trapframe.get_arg(0) as u32;
234 let act_ptr = trapframe.get_arg(1);
235 let oldact_ptr = trapframe.get_arg(2);
236 let _sigsetsize = trapframe.get_arg(3);
237
238 let signal = match LinuxSignal::from_u32(signum) {
240 Some(sig) => sig,
241 None => {
242 trapframe.set_return_value(!0usize); trapframe.increment_pc_next(&task);
244 return !0usize;
245 }
246 };
247
248 let mut signal_state = abi.signal_state.lock();
249
250 if oldact_ptr != 0 {
252 let old_action = signal_state.get_handler(signal);
253 let _ = old_action;
256 }
257
258 if act_ptr != 0 {
260 signal_state.set_handler(signal, SignalAction::Ignore);
266 }
267
268 trapframe.set_return_value(0);
269 trapframe.increment_pc_next(&task);
270 0
271}
272
273pub fn sys_rt_sigprocmask(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
277 let task = mytask().unwrap();
278
279 let how = trapframe.get_arg(0);
280 let set_ptr = trapframe.get_arg(1);
281 let oldset_ptr = trapframe.get_arg(2);
282 let _sigsetsize = trapframe.get_arg(3);
283
284 let mut signal_state = abi.signal_state.lock();
285
286 if oldset_ptr != 0 {
288 let old_mask = signal_state.blocked.raw();
289 let _ = old_mask;
292 }
293
294 if set_ptr != 0 {
296 match how {
301 0 => { }
304 1 => { }
307 2 => { }
310 _ => {
311 trapframe.set_return_value(!0usize); trapframe.increment_pc_next(&task);
313 return !0usize;
314 }
315 }
316 }
317
318 trapframe.set_return_value(0);
319 trapframe.increment_pc_next(&task);
320 0
321}
322
323pub fn process_control_to_signal(control_type: ProcessControlType) -> Option<LinuxSignal> {
325 match control_type {
326 ProcessControlType::Terminate => Some(LinuxSignal::SIGTERM),
327 ProcessControlType::Kill => Some(LinuxSignal::SIGKILL),
328 ProcessControlType::Stop => Some(LinuxSignal::SIGSTOP),
329 ProcessControlType::Continue => Some(LinuxSignal::SIGCONT),
330 ProcessControlType::Interrupt => Some(LinuxSignal::SIGINT),
331 ProcessControlType::Quit => Some(LinuxSignal::SIGQUIT),
332 ProcessControlType::Hangup => Some(LinuxSignal::SIGHUP),
333 ProcessControlType::ChildExit => Some(LinuxSignal::SIGCHLD),
334 ProcessControlType::PipeBroken => Some(LinuxSignal::SIGPIPE),
335 ProcessControlType::Alarm => Some(LinuxSignal::SIGALRM),
336 ProcessControlType::IoReady => Some(LinuxSignal::SIGIO),
337 ProcessControlType::User(sig) => LinuxSignal::from_u32(sig + 32), }
339}
340
341pub fn handle_event_to_signal(event: &Event) -> Option<LinuxSignal> {
343 match &event.content {
344 EventContent::ProcessControl(control_type) => process_control_to_signal(*control_type),
345 _ => None, }
347}
348
349pub fn deliver_signal_to_task(abi: &LinuxRiscv64Abi, signal: LinuxSignal) {
351 let mut signal_state = abi.signal_state.lock();
353 if !signal_state.is_pending(signal) {
354 signal_state.add_pending(signal);
355 }
356}
357
358pub fn get_next_pending_signal(abi: &LinuxRiscv64Abi) -> Option<LinuxSignal> {
360 let signal_state = abi.signal_state.lock();
361 signal_state.next_deliverable_signal()
362}
363
364pub fn process_pending_signals_with_state(
367 signal_state: &mut SignalState,
368 trapframe: &mut Trapframe,
369) -> bool {
370 if let Some(signal) = signal_state.next_deliverable_signal() {
371 let action = signal_state.get_handler(signal);
372
373 signal_state.remove_pending(signal);
375
376 match action {
377 SignalAction::Terminate | SignalAction::ForceTerminate => {
378 crate::early_println!("Signal {}: Terminating task", signal as u32);
382 true
383 }
384 SignalAction::Ignore => {
385 false
387 }
388 SignalAction::Stop => {
389 crate::early_println!("Signal {}: Stopping task", signal as u32);
392 true
393 }
394 SignalAction::Continue => {
395 crate::early_println!("Signal {}: Continuing task", signal as u32);
398 false
399 }
400 SignalAction::Custom(handler_addr) => {
401 crate::early_println!(
403 "Signal {}: Calling custom handler at {:#x}",
404 signal as u32,
405 handler_addr
406 );
407 setup_signal_handler(trapframe, handler_addr, signal);
408 true
409 }
410 }
411 } else {
412 false
413 }
414}
415
416fn setup_signal_handler(trapframe: &mut Trapframe, handler_addr: usize, signal: LinuxSignal) {
418 trapframe.set_arg(0, signal as usize);
427
428 trapframe.epc = handler_addr as u64;
430
431 }
435
436pub fn handle_fatal_signal_immediately(signal: LinuxSignal) -> Result<(), &'static str> {
439 if let Some(task) = crate::task::mytask() {
440 let exit_code = match signal {
441 LinuxSignal::SIGKILL => 128 + 9, LinuxSignal::SIGTERM => 128 + 15, LinuxSignal::SIGINT => 128 + 2, _ => return Err("Not a fatal signal"),
445 };
446
447 crate::early_println!(
448 "Signal {}: Immediately terminating task {} with exit code {}",
449 signal as u32,
450 task.get_id(),
451 exit_code
452 );
453
454 task.exit(exit_code);
456 Ok(())
457 } else {
458 Err("No current task to terminate")
459 }
460}
461
462pub fn is_fatal_signal(signal: LinuxSignal) -> bool {
464 matches!(
465 signal,
466 LinuxSignal::SIGKILL | LinuxSignal::SIGTERM | LinuxSignal::SIGINT
467 )
468}
469
470pub fn sys_tkill(abi: &mut LinuxRiscv64Abi, trapframe: &mut Trapframe) -> usize {
485 let task = match mytask() {
486 Some(t) => t,
487 None => return usize::MAX,
488 };
489
490 let tid = trapframe.get_arg(0) as i32;
491 let sig = trapframe.get_arg(1) as i32;
492
493 trapframe.increment_pc_next(task);
495
496 crate::early_println!(
502 "[sys_tkill] tid={} sig={} - NOOP (signal delivery not implemented)",
503 tid,
504 sig
505 );
506
507 0
510}