Skip to content

Commit 6f828d0

Browse files
authored
Merge pull request #56 from ryanbreen/feature/signals-ipc
Implement POSIX signal handling infrastructure
2 parents f5ee986 + b59857c commit 6f828d0

File tree

26 files changed

+4006
-15
lines changed

26 files changed

+4006
-15
lines changed

docs/planning/signals-ipc-implementation-plan.md

Lines changed: 1397 additions & 0 deletions
Large diffs are not rendered by default.

kernel/src/interrupts/context_switch.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,23 @@ fn restore_userspace_thread_context(
515515
} else {
516516
log::error!("ERROR: Userspace thread {} has no kernel stack!", thread_id);
517517
}
518+
519+
// SIGNAL DELIVERY: Check for pending signals before returning to userspace
520+
// This is the correct point to deliver signals - after context is restored
521+
// but before we actually return to userspace
522+
if crate::signal::delivery::has_deliverable_signals(process) {
523+
if crate::signal::delivery::deliver_pending_signals(
524+
process,
525+
interrupt_frame,
526+
saved_regs,
527+
) {
528+
// Signal was delivered and frame was modified
529+
// If process was terminated, trigger reschedule
530+
if process.is_terminated() {
531+
crate::task::scheduler::set_need_resched();
532+
}
533+
}
534+
}
518535
}
519536
}
520537
}

kernel/src/main.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod memory;
4242
mod per_cpu;
4343
mod process;
4444
mod rtc_test;
45+
mod signal;
4546
mod serial;
4647
mod spinlock;
4748
mod syscall;
@@ -582,6 +583,20 @@ fn kernel_main_continue() -> ! {
582583
test_exec::test_syscall_enosys();
583584
log::info!("ENOSYS test: process scheduled for execution.");
584585

586+
// Test signal handler execution
587+
log::info!("=== SIGNAL TEST: Signal handler execution ===");
588+
test_exec::test_signal_handler();
589+
log::info!("Signal handler test: process scheduled for execution.");
590+
591+
// Test signal handler return via trampoline
592+
log::info!("=== SIGNAL TEST: Signal handler return via trampoline ===");
593+
test_exec::test_signal_return();
594+
log::info!("Signal return test: process scheduled for execution.");
595+
596+
// Test signal register preservation
597+
log::info!("=== SIGNAL TEST: Register preservation across signals ===");
598+
test_exec::test_signal_regs();
599+
585600
// Run fault tests to validate privilege isolation
586601
log::info!("=== FAULT TEST: Running privilege violation tests ===");
587602
userspace_fault_tests::run_fault_tests();

kernel/src/process/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub mod manager;
1212
pub mod process;
1313

1414
pub use manager::ProcessManager;
15-
pub use process::{Process, ProcessId};
15+
pub use process::{Process, ProcessId, ProcessState};
1616

1717
/// Wrapper to log when process manager lock is dropped
1818
pub struct ProcessManagerGuard {

kernel/src/process/process.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::memory::process_memory::ProcessPageTable;
44
use crate::memory::stack::GuardedStack;
5+
use crate::signal::SignalState;
56
use crate::task::thread::Thread;
67
use alloc::boxed::Box;
78
use alloc::string::String;
@@ -90,6 +91,9 @@ pub struct Process {
9091
/// Next hint address for mmap allocation (grows downward)
9192
#[allow(dead_code)]
9293
pub mmap_hint: u64,
94+
95+
/// Signal handling state (pending, blocked, handlers)
96+
pub signals: SignalState,
9397
}
9498

9599
/// Memory usage tracking
@@ -124,6 +128,7 @@ impl Process {
124128
heap_end: 0,
125129
vmas: alloc::vec::Vec::new(),
126130
mmap_hint: crate::memory::vma::MMAP_REGION_END,
131+
signals: SignalState::default(),
127132
}
128133
}
129134

kernel/src/signal/constants.rs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//! Signal numbers and constants following Linux x86_64 conventions
2+
3+
// Standard signals (1-31)
4+
pub const SIGHUP: u32 = 1;
5+
pub const SIGINT: u32 = 2;
6+
pub const SIGQUIT: u32 = 3;
7+
pub const SIGILL: u32 = 4;
8+
pub const SIGTRAP: u32 = 5;
9+
pub const SIGABRT: u32 = 6;
10+
pub const SIGBUS: u32 = 7;
11+
pub const SIGFPE: u32 = 8;
12+
pub const SIGKILL: u32 = 9; // Cannot be caught or blocked
13+
pub const SIGUSR1: u32 = 10;
14+
pub const SIGSEGV: u32 = 11;
15+
pub const SIGUSR2: u32 = 12;
16+
pub const SIGPIPE: u32 = 13;
17+
pub const SIGALRM: u32 = 14;
18+
pub const SIGTERM: u32 = 15;
19+
pub const SIGSTKFLT: u32 = 16;
20+
pub const SIGCHLD: u32 = 17;
21+
pub const SIGCONT: u32 = 18;
22+
pub const SIGSTOP: u32 = 19; // Cannot be caught or blocked
23+
pub const SIGTSTP: u32 = 20;
24+
pub const SIGTTIN: u32 = 21;
25+
pub const SIGTTOU: u32 = 22;
26+
pub const SIGURG: u32 = 23;
27+
pub const SIGXCPU: u32 = 24;
28+
pub const SIGXFSZ: u32 = 25;
29+
pub const SIGVTALRM: u32 = 26;
30+
pub const SIGPROF: u32 = 27;
31+
pub const SIGWINCH: u32 = 28;
32+
pub const SIGIO: u32 = 29;
33+
pub const SIGPWR: u32 = 30;
34+
pub const SIGSYS: u32 = 31;
35+
36+
// Real-time signals (32-64) - for future use
37+
pub const SIGRTMIN: u32 = 32;
38+
pub const SIGRTMAX: u32 = 64;
39+
40+
/// Maximum signal number supported
41+
pub const NSIG: u32 = 64;
42+
43+
// Signal handler special values
44+
/// Default action for the signal
45+
pub const SIG_DFL: u64 = 0;
46+
/// Ignore the signal
47+
pub const SIG_IGN: u64 = 1;
48+
49+
// sigprocmask "how" values
50+
/// Block signals in set
51+
pub const SIG_BLOCK: i32 = 0;
52+
/// Unblock signals in set
53+
pub const SIG_UNBLOCK: i32 = 1;
54+
/// Set blocked signals to set
55+
pub const SIG_SETMASK: i32 = 2;
56+
57+
// sigaction flags
58+
/// Restart interrupted syscalls
59+
#[allow(dead_code)] // Part of POSIX sigaction API, used by userspace
60+
pub const SA_RESTART: u64 = 0x10000000;
61+
/// Don't block signal during handler
62+
pub const SA_NODEFER: u64 = 0x40000000;
63+
/// Provide siginfo_t to handler
64+
#[allow(dead_code)] // Part of POSIX sigaction API, used by userspace
65+
pub const SA_SIGINFO: u64 = 0x00000004;
66+
/// Use alternate signal stack
67+
#[allow(dead_code)] // Part of POSIX sigaction API, used by userspace
68+
pub const SA_ONSTACK: u64 = 0x08000000;
69+
/// Provide restorer function
70+
#[allow(dead_code)] // Part of POSIX sigaction API, used by userspace
71+
pub const SA_RESTORER: u64 = 0x04000000;
72+
73+
/// Convert signal number to bit mask
74+
///
75+
/// Returns 0 for invalid signal numbers (0 or > NSIG)
76+
#[inline]
77+
pub const fn sig_mask(sig: u32) -> u64 {
78+
if sig == 0 || sig > NSIG {
79+
0
80+
} else {
81+
1u64 << (sig - 1)
82+
}
83+
}
84+
85+
/// Signals that cannot be caught, blocked, or ignored
86+
pub const UNCATCHABLE_SIGNALS: u64 = sig_mask(SIGKILL) | sig_mask(SIGSTOP);
87+
88+
/// Check if a signal number is valid
89+
#[inline]
90+
pub const fn is_valid_signal(sig: u32) -> bool {
91+
sig > 0 && sig <= NSIG
92+
}
93+
94+
/// Check if a signal can be caught/blocked
95+
#[inline]
96+
pub const fn is_catchable(sig: u32) -> bool {
97+
sig != SIGKILL && sig != SIGSTOP
98+
}
99+
100+
/// Get signal name for debugging
101+
pub fn signal_name(sig: u32) -> &'static str {
102+
match sig {
103+
SIGHUP => "SIGHUP",
104+
SIGINT => "SIGINT",
105+
SIGQUIT => "SIGQUIT",
106+
SIGILL => "SIGILL",
107+
SIGTRAP => "SIGTRAP",
108+
SIGABRT => "SIGABRT",
109+
SIGBUS => "SIGBUS",
110+
SIGFPE => "SIGFPE",
111+
SIGKILL => "SIGKILL",
112+
SIGUSR1 => "SIGUSR1",
113+
SIGSEGV => "SIGSEGV",
114+
SIGUSR2 => "SIGUSR2",
115+
SIGPIPE => "SIGPIPE",
116+
SIGALRM => "SIGALRM",
117+
SIGTERM => "SIGTERM",
118+
SIGSTKFLT => "SIGSTKFLT",
119+
SIGCHLD => "SIGCHLD",
120+
SIGCONT => "SIGCONT",
121+
SIGSTOP => "SIGSTOP",
122+
SIGTSTP => "SIGTSTP",
123+
SIGTTIN => "SIGTTIN",
124+
SIGTTOU => "SIGTTOU",
125+
SIGURG => "SIGURG",
126+
SIGXCPU => "SIGXCPU",
127+
SIGXFSZ => "SIGXFSZ",
128+
SIGVTALRM => "SIGVTALRM",
129+
SIGPROF => "SIGPROF",
130+
SIGWINCH => "SIGWINCH",
131+
SIGIO => "SIGIO",
132+
SIGPWR => "SIGPWR",
133+
SIGSYS => "SIGSYS",
134+
_ if sig >= SIGRTMIN && sig <= SIGRTMAX => "SIGRT",
135+
_ => "UNKNOWN",
136+
}
137+
}

0 commit comments

Comments
 (0)