Explorar el Código

signal: separate signal.rs into several files

greatbridf hace 9 meses
padre
commit
16acfb40f9

+ 5 - 0
Cargo.lock

@@ -148,6 +148,7 @@ dependencies = [
  "intrusive-collections",
  "itertools",
  "pointers",
+ "posix_types",
 ]
 
 [[package]]
@@ -240,6 +241,10 @@ dependencies = [
 name = "pointers"
 version = "0.1.0"
 
+[[package]]
+name = "posix_types"
+version = "0.1.0"
+
 [[package]]
 name = "prettyplease"
 version = "0.2.25"

+ 1 - 0
Cargo.toml

@@ -17,6 +17,7 @@ eonix_spin_irq = { path = "./crates/eonix_spin_irq" }
 eonix_sync = { path = "./crates/eonix_sync" }
 eonix_log = { path = "./crates/eonix_log" }
 pointers = { path = "./crates/pointers" }
+posix_types = { path = "./crates/posix_types" }
 
 bitflags = "2.6.0"
 intrusive-collections = "0.9.7"

+ 6 - 0
crates/posix_types/Cargo.toml

@@ -0,0 +1,6 @@
+[package]
+name = "posix_types"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]

+ 4 - 0
crates/posix_types/src/lib.rs

@@ -0,0 +1,4 @@
+#![no_std]
+
+pub mod result;
+pub mod signal;

+ 1 - 0
crates/posix_types/src/result.rs

@@ -0,0 +1 @@
+pub enum PosixError {}

+ 3 - 0
crates/posix_types/src/signal.rs

@@ -0,0 +1,3 @@
+mod sig_action;
+
+pub use sig_action::{SigAction, TryFromSigAction};

+ 106 - 0
crates/posix_types/src/signal/sig_action.rs

@@ -0,0 +1,106 @@
+#[repr(C, packed)]
+#[derive(Debug, Clone, Copy)]
+pub struct SigAction {
+    sa_handler: u32,
+    sa_flags: u32,
+    sa_restorer: u32,
+    sa_mask: u64,
+}
+
+pub trait TryFromSigAction: Sized {
+    type Error;
+
+    fn default() -> Self;
+    fn ignore() -> Self;
+    fn new() -> Self;
+
+    fn set_siginfo(self) -> Result<Self, Self::Error>;
+    fn handler(self, handler: usize) -> Result<Self, Self::Error>;
+    fn restorer(self, restorer: usize) -> Result<Self, Self::Error>;
+    fn mask(self, mask: u64) -> Result<Self, Self::Error>;
+}
+
+const SIG_DFL: u32 = 0;
+const SIG_IGN: u32 = 1;
+
+const SA_SIGINFO: u32 = 4;
+const SA_RESTORER: u32 = 0x04000000;
+
+impl SigAction {
+    pub const fn default() -> Self {
+        Self {
+            sa_handler: SIG_DFL,
+            sa_flags: 0,
+            sa_restorer: 0,
+            sa_mask: 0,
+        }
+    }
+
+    pub const fn ignore() -> Self {
+        Self {
+            sa_handler: SIG_IGN,
+            sa_flags: 0,
+            sa_restorer: 0,
+            sa_mask: 0,
+        }
+    }
+
+    pub const fn new() -> Self {
+        Self {
+            sa_handler: 0,
+            sa_flags: 0,
+            sa_restorer: 0,
+            sa_mask: 0,
+        }
+    }
+
+    pub const fn handler(self, handler: usize) -> Self {
+        Self {
+            sa_handler: handler as u32,
+            ..self
+        }
+    }
+
+    pub const fn restorer(self, restorer: usize) -> Self {
+        Self {
+            sa_restorer: restorer as u32,
+            sa_flags: self.sa_flags | SA_RESTORER,
+            ..self
+        }
+    }
+
+    pub const fn mask(self, mask: u64) -> Self {
+        Self {
+            sa_mask: mask,
+            ..self
+        }
+    }
+
+    pub fn try_into<T>(self) -> Result<T, T::Error>
+    where
+        T: TryFromSigAction,
+    {
+        match self.sa_handler {
+            SIG_DFL => Ok(T::default()),
+            SIG_IGN => Ok(T::ignore()),
+            _ => {
+                let mut action = T::new();
+                if self.sa_flags & SA_SIGINFO != 0 {
+                    action = action.set_siginfo()?;
+                }
+
+                action = action.handler(self.sa_handler as usize)?;
+                action = action.restorer(self.sa_restorer as usize)?;
+                action = action.mask(self.sa_mask)?;
+
+                Ok(action)
+            }
+        }
+    }
+}
+
+impl Default for SigAction {
+    fn default() -> Self {
+        Self::default()
+    }
+}

+ 1 - 3
src/kernel/constants.rs

@@ -13,9 +13,6 @@ pub const SIG_BLOCK: u32 = 0;
 pub const SIG_UNBLOCK: u32 = 1;
 pub const SIG_SETMASK: u32 = 2;
 
-pub const SA_SIGINFO: u32 = 4;
-pub const SA_RESTORER: u32 = 0x04000000;
-
 pub const CLOCK_REALTIME: u32 = 0;
 pub const CLOCK_MONOTONIC: u32 = 1;
 
@@ -25,6 +22,7 @@ pub const ENXIO: u32 = 6;
 pub const ENOEXEC: u32 = 8;
 pub const EFAULT: u32 = 14;
 pub const EEXIST: u32 = 17;
+pub const EINVAL: u32 = 22;
 pub const ENOSYS: u32 = 38;
 
 #[allow(dead_code)]

+ 8 - 1
src/kernel/interrupt.rs

@@ -1,12 +1,13 @@
 use super::cpu::local_cpu;
 use super::mem::handle_page_fault;
 use super::syscall::handle_syscall32;
-use super::task::{ProcessList, Signal};
+use super::task::{ProcessList, Signal, Thread};
 use super::timer::timer_interrupt;
 use crate::bindings::root::EINVAL;
 use crate::{driver::Port8, prelude::*};
 use alloc::sync::Arc;
 use arch::{ExtendedContext, InterruptContext};
+use eonix_runtime::task::Task;
 use eonix_spin_irq::SpinIrq as _;
 
 const PIC1_COMMAND: Port8 = Port8::new(0x20);
@@ -59,6 +60,12 @@ pub extern "C" fn interrupt_handler(
         // IRQ
         no => irq_handler(no as usize - 0x20),
     }
+
+    if int_stack.cs & 0x3 != 0 {
+        if Thread::current().signal_list.has_pending_signal() {
+            Task::block_on(Thread::current().signal_list.handle(int_stack, ext_ctx));
+        }
+    }
 }
 
 pub fn register_irq_handler<F>(irqno: i32, handler: F) -> Result<(), u32>

+ 35 - 16
src/kernel/mem/address.rs

@@ -1,26 +1,26 @@
+use arch::PAGE_SIZE;
 use core::{
     cmp::Ordering,
     fmt::{self, Debug, Formatter},
     ops::{Add, RangeBounds, Sub},
 };
 
-#[repr(C)]
+#[repr(transparent)]
 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
 pub struct PAddr(pub usize);
 
-#[repr(C)]
+#[repr(transparent)]
 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
 pub struct VAddr(pub usize);
 
-#[repr(C)]
+#[repr(transparent)]
 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
 pub struct PFN(pub usize);
 
-#[repr(C)]
+#[repr(transparent)]
 #[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
 pub struct VPN(pub usize);
 
-const PAGE_SIZE: usize = 4096;
 const PAGE_SIZE_BITS: usize = 12;
 const USER_SPACE_MEMORY_TOP: VAddr = VAddr(0x8000_0000_0000);
 
@@ -129,32 +129,51 @@ impl PFN {
 impl VAddr {
     pub const NULL: Self = Self(0);
 
-    pub fn floor_vpn(&self) -> VPN {
+    pub const fn floor_vpn(&self) -> VPN {
         VPN(self.0 / PAGE_SIZE)
     }
 
-    pub fn ceil_vpn(&self) -> VPN {
+    pub const fn ceil_vpn(&self) -> VPN {
         VPN((self.0 - 1 + PAGE_SIZE) / PAGE_SIZE)
     }
 
-    pub fn page_offset(&self) -> usize {
-        self.0 & (PAGE_SIZE - 1)
+    pub const fn page_offset(self) -> usize {
+        let Self(addr) = self;
+        addr & (PAGE_SIZE - 1)
     }
 
-    pub fn is_aligned(&self) -> bool {
+    pub const fn is_aligned(&self) -> bool {
         self.page_offset() == 0
     }
 
-    pub fn is_user(&self) -> bool {
-        self.0 != 0 && self < &USER_SPACE_MEMORY_TOP
+    pub const fn is_user(self) -> bool {
+        const USER_SPACE_MEMORY_TOP_ADDR: usize = const { USER_SPACE_MEMORY_TOP.0 };
+
+        match self {
+            Self(0) => false,
+            Self(..USER_SPACE_MEMORY_TOP_ADDR) => true,
+            _ => false,
+        }
+    }
+
+    pub const fn floor(self) -> Self {
+        self.floor_to(PAGE_SIZE)
+    }
+
+    pub const fn ceil(self) -> Self {
+        self.ceil_to(PAGE_SIZE)
     }
 
-    pub fn floor(&self) -> Self {
-        VAddr(self.0 & !(PAGE_SIZE - 1))
+    /// Aligns the address to the nearest lower multiple of `size`.
+    pub const fn floor_to(self, size: usize) -> Self {
+        let Self(addr) = self;
+        Self(addr / size * size)
     }
 
-    pub fn ceil(&self) -> Self {
-        VAddr((self.0 + (PAGE_SIZE - 1)) & !(PAGE_SIZE - 1))
+    /// Aligns the address to the nearest lower multiple of `size`.
+    pub const fn ceil_to(self, size: usize) -> Self {
+        let Self(addr) = self;
+        Self(addr.div_ceil(size) * size)
     }
 }
 

+ 0 - 6
src/kernel/syscall.rs

@@ -178,8 +178,6 @@ macro_rules! register_syscall {
     };
 }
 
-use super::task::Thread;
-
 pub(self) use {arg_register, define_syscall32, format_expand, register_syscall, syscall32_call};
 
 #[allow(dead_code)]
@@ -245,8 +243,4 @@ pub fn handle_syscall32(
             int_stack.r15 = 0;
         }
     }
-
-    if Thread::current().signal_list.has_pending_signal() {
-        Thread::current().signal_list.handle(int_stack, ext_ctx);
-    }
 }

+ 19 - 43
src/kernel/syscall/procops.rs

@@ -7,14 +7,15 @@ use crate::kernel::constants::{
 };
 use crate::kernel::mem::{Page, PageBuffer, VAddr};
 use crate::kernel::task::{
-    KernelStack, ProcessBuilder, ProcessList, Signal, SignalAction, Thread, ThreadBuilder,
-    ThreadRunnable, UserDescriptor, WaitObject, WaitType,
+    KernelStack, ProcessBuilder, ProcessList, Signal, SignalAction, SignalMask, Thread,
+    ThreadBuilder, ThreadRunnable, UserDescriptor, WaitObject, WaitType,
 };
 use crate::kernel::user::dataflow::UserString;
 use crate::kernel::user::{UserPointer, UserPointerMut};
 use crate::kernel::vfs::dentry::Dentry;
 use crate::kernel::vfs::{self, FsContext};
 use crate::path::Path;
+use crate::SIGNAL_NOW;
 use crate::{kernel::user::dataflow::UserBuffer, prelude::*};
 use alloc::borrow::ToOwned;
 use alloc::ffi::CString;
@@ -24,6 +25,7 @@ use bitflags::bitflags;
 use eonix_runtime::scheduler::Scheduler;
 use eonix_runtime::task::Task;
 use eonix_sync::AsProof as _;
+use posix_types::signal::SigAction;
 
 fn do_umask(mask: u32) -> KResult<u32> {
     let context = FsContext::get_current();
@@ -362,13 +364,13 @@ fn do_rt_sigprocmask(how: u32, set: *mut u64, oldset: *mut u64, sigsetsize: usiz
         return Err(EINVAL);
     }
 
-    let old_mask = Thread::current().signal_list.get_mask();
+    let old_mask = u64::from(Thread::current().signal_list.get_mask());
     if !oldset.is_null() {
         UserPointerMut::new(oldset)?.write(old_mask)?;
     }
 
     let new_mask = if !set.is_null() {
-        UserPointer::new(set)?.read()?
+        SignalMask::from(UserPointer::new(set)?.read()?)
     } else {
         return Ok(());
     };
@@ -383,58 +385,32 @@ fn do_rt_sigprocmask(how: u32, set: *mut u64, oldset: *mut u64, sigsetsize: usiz
     Ok(())
 }
 
-#[repr(C, packed)]
-#[derive(Debug, Clone, Copy)]
-struct UserSignalAction {
-    sa_handler: u32,
-    sa_flags: u32,
-    sa_restorer: u32,
-    sa_mask: u64,
-}
-
-impl From<UserSignalAction> for SignalAction {
-    fn from(from: UserSignalAction) -> SignalAction {
-        SignalAction {
-            sa_handler: from.sa_handler as usize,
-            sa_flags: from.sa_flags as usize,
-            sa_mask: from.sa_mask as usize,
-            sa_restorer: from.sa_restorer as usize,
-        }
-    }
-}
-
-impl From<SignalAction> for UserSignalAction {
-    fn from(from: SignalAction) -> UserSignalAction {
-        UserSignalAction {
-            sa_handler: from.sa_handler as u32,
-            sa_flags: from.sa_flags as u32,
-            sa_mask: from.sa_mask as u64,
-            sa_restorer: from.sa_restorer as u32,
-        }
-    }
-}
-
 fn do_rt_sigaction(
     signum: u32,
-    act: *const UserSignalAction,
-    oldact: *mut UserSignalAction,
+    act: *const SigAction,
+    oldact: *mut SigAction,
     sigsetsize: usize,
 ) -> KResult<()> {
     let signal = Signal::try_from(signum)?;
-    if sigsetsize != size_of::<u64>() || signal.is_now() {
+    if sigsetsize != size_of::<u64>() {
         return Err(EINVAL);
     }
 
-    let old_action = Thread::current().signal_list.get_handler(signal);
+    // SIGKILL and SIGSTOP MUST not be set for a handler.
+    if matches!(signal, SIGNAL_NOW!()) {
+        return Err(EINVAL);
+    }
+
+    let old_action = Thread::current().signal_list.get_action(signal);
     if !oldact.is_null() {
         UserPointerMut::new(oldact)?.write(old_action.into())?;
     }
 
     if !act.is_null() {
         let new_action = UserPointer::new(act)?.read()?;
-        Thread::current()
-            .signal_list
-            .set_handler(signal, &new_action.into())?;
+        let action: SignalAction = new_action.try_into()?;
+
+        Thread::current().signal_list.set_action(signal, action)?;
     }
 
     Ok(())
@@ -569,7 +545,7 @@ define_syscall32!(sys_tkill, do_tkill, tid: u32, sig: u32);
 define_syscall32!(sys_rt_sigprocmask, do_rt_sigprocmask,
     how: u32, set: *mut u64, oldset: *mut u64, sigsetsize: usize);
 define_syscall32!(sys_rt_sigaction, do_rt_sigaction,
-    signum: u32, act: *const UserSignalAction, oldact: *mut UserSignalAction, sigsetsize: usize);
+    signum: u32, act: *const SigAction, oldact: *mut SigAction, sigsetsize: usize);
 define_syscall32!(sys_prlimit64, do_prlimit64,
     pid: u32, resource: u32, new_limit: *const RLimit, old_limit: *mut RLimit);
 define_syscall32!(sys_getrlimit, do_getrlimit, resource: u32, rlimit: *mut RLimit);

+ 1 - 1
src/kernel/task.rs

@@ -11,5 +11,5 @@ pub use process::{Process, ProcessBuilder, WaitObject, WaitType};
 pub use process_group::ProcessGroup;
 pub use process_list::ProcessList;
 pub use session::Session;
-pub use signal::{Signal, SignalAction};
+pub use signal::{Signal, SignalAction, SignalMask};
 pub use thread::{Thread, ThreadBuilder, ThreadRunnable, UserDescriptor};

+ 2 - 1
src/kernel/task/process.rs

@@ -7,6 +7,7 @@ use crate::{
     prelude::*,
     rcu::{rcu_sync, RCUPointer, RCUReadGuard},
     sync::CondVar,
+    SIGNAL_COREDUMP,
 };
 use alloc::{
     collections::{btree_map::BTreeMap, vec_deque::VecDeque},
@@ -111,7 +112,7 @@ impl WaitType {
     pub fn to_wstatus(self) -> u32 {
         match self {
             WaitType::Exited(status) => (status & 0xff) << 8,
-            WaitType::Signaled(signal) if signal.is_coredump() => u32::from(signal) | 0x80,
+            WaitType::Signaled(signal @ SIGNAL_COREDUMP!()) => u32::from(signal) | 0x80,
             WaitType::Signaled(signal) => u32::from(signal),
             WaitType::Stopped(signal) => 0x7f | (u32::from(signal) << 8),
             WaitType::Continued => 0xffff,

+ 74 - 272
src/kernel/task/signal.rs

@@ -1,77 +1,31 @@
+mod signal;
+mod signal_action;
+mod signal_mask;
+
 use super::{ProcessList, Thread, WaitObject, WaitType};
-use crate::{
-    io::BufferFill,
-    kernel::{
-        constants::{SA_RESTORER, SA_SIGINFO},
-        user::{dataflow::UserBuffer, UserPointer},
-    },
-    prelude::*,
-};
-use alloc::collections::{binary_heap::BinaryHeap, btree_map::BTreeMap};
+use crate::{kernel::user::UserPointer, prelude::*};
+use alloc::collections::binary_heap::BinaryHeap;
 use arch::{ExtendedContext, InterruptContext};
 use bindings::{EFAULT, EINVAL};
 use core::{cmp::Reverse, task::Waker};
 use eonix_runtime::task::Task;
 use eonix_sync::AsProof as _;
 use intrusive_collections::UnsafeRef;
+use signal_action::SignalActionList;
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Signal(u32);
-
-#[allow(dead_code)]
-impl Signal {
-    pub const SIGHUP: Signal = Signal(1);
-    pub const SIGINT: Signal = Signal(2);
-    pub const SIGQUIT: Signal = Signal(3);
-    pub const SIGILL: Signal = Signal(4);
-    pub const SIGTRAP: Signal = Signal(5);
-    pub const SIGABRT: Signal = Signal(6);
-    pub const SIGIOT: Signal = Signal(6);
-    pub const SIGBUS: Signal = Signal(7);
-    pub const SIGFPE: Signal = Signal(8);
-    pub const SIGKILL: Signal = Signal(9);
-    pub const SIGUSR1: Signal = Signal(10);
-    pub const SIGSEGV: Signal = Signal(11);
-    pub const SIGUSR2: Signal = Signal(12);
-    pub const SIGPIPE: Signal = Signal(13);
-    pub const SIGALRM: Signal = Signal(14);
-    pub const SIGTERM: Signal = Signal(15);
-    pub const SIGSTKFLT: Signal = Signal(16);
-    pub const SIGCHLD: Signal = Signal(17);
-    pub const SIGCONT: Signal = Signal(18);
-    pub const SIGSTOP: Signal = Signal(19);
-    pub const SIGTSTP: Signal = Signal(20);
-    pub const SIGTTIN: Signal = Signal(21);
-    pub const SIGTTOU: Signal = Signal(22);
-    pub const SIGURG: Signal = Signal(23);
-    pub const SIGXCPU: Signal = Signal(24);
-    pub const SIGXFSZ: Signal = Signal(25);
-    pub const SIGVTALRM: Signal = Signal(26);
-    pub const SIGPROF: Signal = Signal(27);
-    pub const SIGWINCH: Signal = Signal(28);
-    pub const SIGIO: Signal = Signal(29);
-    pub const SIGPOLL: Signal = Signal(29);
-    pub const SIGPWR: Signal = Signal(30);
-    pub const SIGSYS: Signal = Signal(31);
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct SignalAction {
-    pub sa_handler: usize,
-    pub sa_flags: usize,
-    pub sa_restorer: usize,
-    pub sa_mask: usize,
-}
+pub use signal::{Signal, SIGNAL_IGNORE, SIGNAL_NOW, SIGNAL_STOP};
+pub use signal_action::SignalAction;
+pub use signal_mask::SignalMask;
 
 struct SignalListInner {
-    mask: u64,
+    mask: SignalMask,
     pending: BinaryHeap<Reverse<Signal>>,
 
     signal_waker: Option<UnsafeRef<dyn Fn() + Send + Sync>>,
     stop_waker: Option<Waker>,
 
     // TODO!!!!!: Signal disposition should be per-process.
-    handlers: BTreeMap<Signal, SignalAction>,
+    actions: SignalActionList,
 }
 
 pub struct SignalList {
@@ -93,7 +47,7 @@ impl Clone for SignalList {
                 pending: BinaryHeap::new(),
                 signal_waker: None,
                 stop_waker: None,
-                handlers: inner.handlers.clone(),
+                actions: inner.actions.clone(),
             }),
         }
     }
@@ -105,172 +59,36 @@ pub enum RaiseResult {
     Masked,
 }
 
-impl Signal {
-    const fn is_ignore(&self) -> bool {
-        match *self {
-            Self::SIGCHLD | Self::SIGURG | Self::SIGWINCH => true,
-            _ => false,
-        }
-    }
-
-    pub const fn is_now(&self) -> bool {
-        match *self {
-            Self::SIGKILL | Self::SIGSTOP => true,
-            _ => false,
-        }
-    }
-
-    pub const fn is_coredump(&self) -> bool {
-        match *self {
-            Self::SIGQUIT
-            | Self::SIGILL
-            | Self::SIGABRT
-            | Self::SIGFPE
-            | Self::SIGSEGV
-            | Self::SIGBUS
-            | Self::SIGTRAP
-            | Self::SIGSYS
-            | Self::SIGXCPU
-            | Self::SIGXFSZ => true,
-            _ => false,
-        }
-    }
-
-    fn to_mask(&self) -> u64 {
-        1 << (self.0 - 1)
-    }
-}
-
-impl TryFrom<u32> for Signal {
-    type Error = u32;
-
-    fn try_from(signum: u32) -> Result<Self, Self::Error> {
-        if signum > 0 && signum <= 64 {
-            Ok(Self(signum))
-        } else {
-            Err(EINVAL)
-        }
-    }
-}
-
-impl From<Signal> for u32 {
-    fn from(signal: Signal) -> Self {
-        let Signal(signum) = signal;
-        signum
-    }
-}
-
-impl SignalAction {
-    fn default_action() -> Self {
-        Self {
-            sa_handler: 0,
-            sa_flags: 0,
-            sa_restorer: 0,
-            sa_mask: 0,
-        }
-    }
-
-    fn is_ignore(&self) -> bool {
-        const SIG_IGN: usize = 1;
-        self.sa_handler == SIG_IGN
-    }
-
-    fn is_default(&self) -> bool {
-        const SIG_DFL: usize = 0;
-        self.sa_handler == SIG_DFL
-    }
-
-    /// # Might Sleep
-    fn handle(
-        &self,
-        signal: Signal,
-        old_mask: u64,
-        int_stack: &mut InterruptContext,
-        ext_ctx: &mut ExtendedContext,
-    ) -> KResult<()> {
-        if self.sa_flags & SA_RESTORER as usize == 0 {
-            return Err(EINVAL);
-        }
-
-        const CONTEXT_SIZE: usize = size_of::<InterruptContext>()
-            + size_of::<ExtendedContext>()
-            + size_of::<usize>() // old_mask
-            + size_of::<u32>(); // `sa_handler` argument: `signum`
-
-        // Save current interrupt context to 128 bytes above current user stack
-        // and align to 16 bytes. Then we push the return address of the restorer.
-        // TODO!!!: Determine the size of the return address
-        let sp = ((int_stack.rsp as usize - 128 - CONTEXT_SIZE) & !0xf) - size_of::<u32>();
-        let restorer_address: u32 = self.sa_restorer as u32;
-        let mut stack = UserBuffer::new(sp as *mut u8, CONTEXT_SIZE + size_of::<u32>())?;
-
-        stack.copy(&restorer_address)?.ok_or(EFAULT)?; // Restorer address
-        stack.copy(&u32::from(signal))?.ok_or(EFAULT)?; // Restorer address
-        stack.copy(&old_mask)?.ok_or(EFAULT)?; // Original signal mask
-        stack.copy(ext_ctx)?.ok_or(EFAULT)?; // MMX registers
-        stack.copy(int_stack)?.ok_or(EFAULT)?; // Interrupt stack
-
-        int_stack.rip = self.sa_handler as u64;
-        int_stack.rsp = sp as u64;
-        Ok(())
-    }
-}
-
 impl SignalListInner {
-    fn get_mask(&self) -> u64 {
-        self.mask
-    }
-
-    fn set_mask(&mut self, mask: u64) {
-        self.mask = mask;
-    }
-
-    fn mask(&mut self, mask: u64) {
-        self.set_mask(self.mask | mask)
-    }
-
-    fn unmask(&mut self, mask: u64) {
-        self.set_mask(self.mask & !mask)
-    }
-
-    fn is_masked(&self, signal: Signal) -> bool {
-        self.mask & signal.to_mask() != 0
-    }
-
     fn pop(&mut self) -> Option<Signal> {
         self.pending.pop().map(|Reverse(signal)| signal)
     }
 
     fn raise(&mut self, signal: Signal) -> RaiseResult {
-        if self.is_masked(signal) {
+        if self.mask.include(signal) {
             return RaiseResult::Masked;
         }
 
-        match self.handlers.get(&signal) {
-            // Ignore action
-            Some(handler) if handler.is_ignore() => return RaiseResult::Finished,
-            // Default action
-            None if signal.is_ignore() => return RaiseResult::Finished,
-            _ => {}
-        }
-
-        self.mask(signal.to_mask());
-        self.pending.push(Reverse(signal));
-
-        match signal {
-            Signal::SIGCONT => {
-                self.stop_waker.take().map(|waker| waker.wake());
-            }
+        match (signal, self.actions.get(signal)) {
+            (_, SignalAction::Ignore) => {}
+            (SIGNAL_IGNORE!(), SignalAction::Default) => {}
             _ => {
-                // If we don't have a waker here, we are not permitted to be woken up.
-                // We would run in the end anyway.
-                if let Some(waker) = self.signal_waker.take() {
-                    waker();
+                self.mask.mask(SignalMask::from(signal));
+                self.pending.push(Reverse(signal));
+
+                if matches!(signal, Signal::SIGCONT) {
+                    self.stop_waker.take().map(|waker| waker.wake());
+                } else {
+                    // If we don't have a waker here, we are not permitted to be woken up.
+                    // We would run in the end anyway.
+                    if let Some(waker) = self.signal_waker.take() {
+                        waker();
+                    }
                 }
             }
         }
 
-        return RaiseResult::Finished;
+        RaiseResult::Finished
     }
 }
 
@@ -278,53 +96,42 @@ impl SignalList {
     pub fn new() -> Self {
         Self {
             inner: Spin::new(SignalListInner {
-                mask: 0,
+                mask: SignalMask::empty(),
                 pending: BinaryHeap::new(),
                 signal_waker: None,
                 stop_waker: None,
-                handlers: BTreeMap::new(),
+                actions: SignalActionList::new(),
             }),
         }
     }
 
-    pub fn get_mask(&self) -> u64 {
-        self.inner.lock().get_mask()
+    pub fn get_mask(&self) -> SignalMask {
+        self.inner.lock().mask
     }
 
-    pub fn set_mask(&self, mask: u64) {
-        self.inner.lock().set_mask(mask)
+    pub fn set_mask(&self, mask: SignalMask) {
+        self.inner.lock().mask = mask;
     }
 
-    pub fn mask(&self, mask: u64) {
-        self.inner.lock().set_mask(mask)
+    pub fn mask(&self, mask: SignalMask) {
+        self.inner.lock().mask.mask(mask)
     }
 
-    pub fn unmask(&self, mask: u64) {
-        self.inner.lock().unmask(mask)
+    pub fn unmask(&self, mask: SignalMask) {
+        self.inner.lock().mask.unmask(mask)
     }
 
-    pub fn set_handler(&self, signal: Signal, action: &SignalAction) -> KResult<()> {
-        if signal.is_now() || action.sa_flags & SA_SIGINFO as usize != 0 {
+    pub fn set_action(&self, signal: Signal, action: SignalAction) -> KResult<()> {
+        if matches!(signal, SIGNAL_NOW!()) {
             return Err(EINVAL);
         }
 
-        let mut inner = self.inner.lock();
-        if action.is_default() {
-            inner.handlers.remove(&signal);
-        } else {
-            inner.handlers.insert(signal, action.clone());
-        }
-
+        self.inner.lock().actions.set(signal, action);
         Ok(())
     }
 
-    pub fn get_handler(&self, signal: Signal) -> SignalAction {
-        self.inner
-            .lock()
-            .handlers
-            .get(&signal)
-            .cloned()
-            .unwrap_or_else(SignalAction::default_action)
+    pub fn get_action(&self, signal: Signal) -> SignalAction {
+        self.inner.lock().actions.get(signal)
     }
 
     pub fn set_signal_waker(&self, waker: Option<UnsafeRef<dyn Fn() + Send + Sync>>) {
@@ -335,10 +142,7 @@ impl SignalList {
     /// Clear all signals except for `SIG_IGN`.
     /// This is used when `execve` is called.
     pub fn clear_non_ignore(&self) {
-        self.inner
-            .lock()
-            .handlers
-            .retain(|_, action| action.is_ignore());
+        self.inner.lock().actions.remove_non_ignore();
     }
 
     /// Clear all pending signals.
@@ -361,7 +165,7 @@ impl SignalList {
     /// # Safety
     /// This function might never return. Caller must make sure that local variables
     /// that own resources are dropped before calling this function.
-    pub fn handle(&self, int_stack: &mut InterruptContext, ext_ctx: &mut ExtendedContext) {
+    pub async fn handle(&self, int_stack: &mut InterruptContext, ext_ctx: &mut ExtendedContext) {
         loop {
             let signal = {
                 let signal = match self.inner.lock().pop() {
@@ -369,26 +173,25 @@ impl SignalList {
                     None => return,
                 };
 
-                let handler = self.inner.lock().handlers.get(&signal).cloned();
-                if let Some(handler) = handler {
-                    if !signal.is_now() {
-                        let old_mask = {
-                            let mut inner = self.inner.lock();
-                            let old_mask = inner.mask;
-                            inner.mask(handler.sa_mask as u64);
-                            old_mask
-                        };
-                        let result = handler.handle(signal, old_mask, int_stack, ext_ctx);
-                        if result.is_err() {
-                            self.inner.lock().set_mask(old_mask);
-                        }
-                        match result {
-                            Err(EFAULT) => self.inner.lock().raise(Signal::SIGSEGV),
-                            Err(_) => self.inner.lock().raise(Signal::SIGSYS),
-                            Ok(()) => return,
-                        };
-                        continue;
+                let handler = self.inner.lock().actions.get(signal);
+                if let SignalAction::SimpleHandler { mask, .. } = &handler {
+                    let old_mask = {
+                        let mut inner = self.inner.lock();
+                        let old_mask = inner.mask;
+                        inner.mask.mask(*mask);
+                        old_mask
+                    };
+
+                    let result = handler.handle(signal, old_mask, int_stack, ext_ctx);
+                    if result.is_err() {
+                        self.inner.lock().mask = old_mask;
                     }
+                    match result {
+                        Err(EFAULT) => self.inner.lock().raise(Signal::SIGSEGV),
+                        Err(_) => self.inner.lock().raise(Signal::SIGSYS),
+                        Ok(()) => return,
+                    };
+                    continue;
                 }
 
                 // TODO: The default signal handling process should be atomic.
@@ -396,13 +199,17 @@ impl SignalList {
                 // Default actions include stopping the thread, continuing the thread and
                 // terminating the process. All these actions will block the thread or return
                 // to the thread immediately. So we can unmask these signals now.
-                self.inner.lock().unmask(signal.to_mask());
+                self.inner.lock().mask.unmask(SignalMask::from(signal));
                 signal
             };
 
             // Default actions.
             match signal {
-                Signal::SIGSTOP | Signal::SIGTSTP | Signal::SIGTTIN | Signal::SIGTTOU => {
+                SIGNAL_IGNORE!() => {}
+                Signal::SIGCONT => {
+                    // SIGCONT wakeup is done in `raise()`. So no further action needed here.
+                }
+                SIGNAL_STOP!() => {
                     let thread = Thread::current();
                     if let Some(parent) = thread.process.parent.load() {
                         parent.notify(
@@ -410,7 +217,7 @@ impl SignalList {
                                 pid: thread.process.pid,
                                 code: WaitType::Stopped(signal),
                             },
-                            Task::block_on(ProcessList::get().read()).prove(),
+                            ProcessList::get().read().await.prove(),
                         );
                     }
 
@@ -434,16 +241,11 @@ impl SignalList {
                                 pid: thread.process.pid,
                                 code: WaitType::Continued,
                             },
-                            Task::block_on(ProcessList::get().read()).prove(),
+                            ProcessList::get().read().await.prove(),
                         );
                     }
                 }
-                Signal::SIGCONT => {}
-                Signal::SIGKILL => ProcessList::kill_current(signal),
-                // Ignored
-                Signal::SIGCHLD | Signal::SIGURG | Signal::SIGWINCH => {}
-                // TODO!!!!!!: Check exit status format.
-                s if s.is_coredump() => ProcessList::kill_current(signal),
+                // Default to terminate the process.
                 signal => ProcessList::kill_current(signal),
             }
         }
@@ -465,7 +267,7 @@ impl SignalList {
         *ext_ctx = UserPointer::<ExtendedContext>::new_vaddr(old_mmxregs_vaddr)?.read()?;
         *int_stack = UserPointer::<InterruptContext>::new_vaddr(old_int_stack_vaddr)?.read()?;
 
-        self.inner.lock().set_mask(old_mask);
+        self.inner.lock().mask = SignalMask::from(old_mask);
         Ok(int_stack.rax as usize)
     }
 }

+ 114 - 0
src/kernel/task/signal/signal.rs

@@ -0,0 +1,114 @@
+use crate::kernel::constants::EINVAL;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Signal(u32);
+
+impl Signal {
+    pub const SIGHUP: Signal = Signal(1);
+    pub const SIGINT: Signal = Signal(2);
+    pub const SIGQUIT: Signal = Signal(3);
+    pub const SIGILL: Signal = Signal(4);
+    pub const SIGTRAP: Signal = Signal(5);
+    pub const SIGABRT: Signal = Signal(6);
+    pub const SIGIOT: Signal = Signal(6);
+    pub const SIGBUS: Signal = Signal(7);
+    pub const SIGFPE: Signal = Signal(8);
+    pub const SIGKILL: Signal = Signal(9);
+    pub const SIGUSR1: Signal = Signal(10);
+    pub const SIGSEGV: Signal = Signal(11);
+    pub const SIGUSR2: Signal = Signal(12);
+    pub const SIGPIPE: Signal = Signal(13);
+    pub const SIGALRM: Signal = Signal(14);
+    pub const SIGTERM: Signal = Signal(15);
+    pub const SIGSTKFLT: Signal = Signal(16);
+    pub const SIGCHLD: Signal = Signal(17);
+    pub const SIGCONT: Signal = Signal(18);
+    pub const SIGSTOP: Signal = Signal(19);
+    pub const SIGTSTP: Signal = Signal(20);
+    pub const SIGTTIN: Signal = Signal(21);
+    pub const SIGTTOU: Signal = Signal(22);
+    pub const SIGURG: Signal = Signal(23);
+    pub const SIGXCPU: Signal = Signal(24);
+    pub const SIGXFSZ: Signal = Signal(25);
+    pub const SIGVTALRM: Signal = Signal(26);
+    pub const SIGPROF: Signal = Signal(27);
+    pub const SIGWINCH: Signal = Signal(28);
+    pub const SIGIO: Signal = Signal(29);
+    pub const SIGPOLL: Signal = Signal(29);
+    pub const SIGPWR: Signal = Signal(30);
+    pub const SIGSYS: Signal = Signal(31);
+
+    pub const SIGNUM_MIN: u32 = 1;
+    pub const SIGNUM_MAX: u32 = 64;
+}
+
+#[macro_export]
+macro_rules! SIGNAL_IGNORE {
+    () => {
+        $crate::kernel::task::Signal::SIGCHLD
+            | $crate::kernel::task::Signal::SIGURG
+            | $crate::kernel::task::Signal::SIGWINCH
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_NOW {
+    () => {
+        $crate::kernel::task::Signal::SIGKILL | $crate::kernel::task::Signal::SIGSTOP
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_COREDUMP {
+    () => {
+        $crate::kernel::task::Signal::SIGQUIT
+            | $crate::kernel::task::Signal::SIGILL
+            | $crate::kernel::task::Signal::SIGABRT
+            | $crate::kernel::task::Signal::SIGFPE
+            | $crate::kernel::task::Signal::SIGSEGV
+            | $crate::kernel::task::Signal::SIGBUS
+            | $crate::kernel::task::Signal::SIGTRAP
+            | $crate::kernel::task::Signal::SIGSYS
+            | $crate::kernel::task::Signal::SIGXCPU
+            | $crate::kernel::task::Signal::SIGXFSZ
+    };
+}
+
+#[macro_export]
+macro_rules! SIGNAL_STOP {
+    () => {
+        $crate::kernel::task::Signal::SIGSTOP
+            | $crate::kernel::task::Signal::SIGTSTP
+            | $crate::kernel::task::Signal::SIGTTIN
+            | $crate::kernel::task::Signal::SIGTTOU
+    };
+}
+
+impl TryFrom<u32> for Signal {
+    type Error = u32;
+
+    fn try_from(signum: u32) -> Result<Self, Self::Error> {
+        match signum {
+            Self::SIGNUM_MIN..=Self::SIGNUM_MAX => Ok(Self(signum)),
+            _ => Err(EINVAL),
+        }
+    }
+}
+
+impl From<Signal> for u32 {
+    fn from(signal: Signal) -> Self {
+        let Signal(signum) = signal;
+        signum
+    }
+}
+
+impl From<Signal> for SignalMask {
+    fn from(signal: Signal) -> Self {
+        let signum = u32::from(signal);
+        SignalMask::new(1 << (signum - 1))
+    }
+}
+
+use super::SignalMask;
+
+pub use {SIGNAL_IGNORE, SIGNAL_NOW, SIGNAL_STOP};

+ 201 - 0
src/kernel/task/signal/signal_action.rs

@@ -0,0 +1,201 @@
+use super::{KResult, Signal, SignalMask};
+use crate::{
+    io::BufferFill as _,
+    kernel::{
+        constants::{EFAULT, EINVAL, ENOSYS},
+        mem::VAddr,
+        user::UserBuffer,
+    },
+    SIGNAL_NOW,
+};
+use alloc::collections::btree_map::BTreeMap;
+use arch::{ExtendedContext, InterruptContext};
+use core::num::NonZero;
+use posix_types::signal::{SigAction, TryFromSigAction};
+
+#[derive(Debug, Clone, Copy)]
+pub enum SignalAction {
+    Default,
+    Ignore,
+    SimpleHandler {
+        handler: VAddr,
+        restorer: Option<VAddr>,
+        mask: SignalMask,
+    },
+}
+
+#[derive(Debug)]
+pub struct SignalActionList {
+    actions: BTreeMap<Signal, SignalAction>,
+}
+
+impl SignalActionList {
+    pub const fn new() -> Self {
+        Self {
+            actions: BTreeMap::new(),
+        }
+    }
+
+    pub fn set(&mut self, signal: Signal, action: SignalAction) {
+        debug_assert!(
+            !matches!(signal, SIGNAL_NOW!()),
+            "SIGSTOP and SIGKILL should not be set for a handler."
+        );
+        match action {
+            SignalAction::Default => self.actions.remove(&signal),
+            _ => self.actions.insert(signal, action),
+        };
+    }
+
+    pub fn get(&self, signal: Signal) -> SignalAction {
+        match self.actions.get(&signal) {
+            None => SignalAction::Default,
+            Some(action) => action.clone(),
+        }
+    }
+
+    pub fn remove_non_ignore(&mut self) {
+        // Remove all custom handlers except for the ignore action.
+        // Default handlers should never appear in the list so we don't consider that.
+        self.actions
+            .retain(|_, action| matches!(action, SignalAction::Ignore));
+    }
+}
+
+impl SignalAction {
+    /// # Might Sleep
+    pub(super) fn handle(
+        self,
+        signal: Signal,
+        old_mask: SignalMask,
+        int_stack: &mut InterruptContext,
+        ext_ctx: &mut ExtendedContext,
+    ) -> KResult<()> {
+        // TODO: The sizes of the context structures should be arch-specific.
+        const CONTEXT_SIZE: usize = size_of::<InterruptContext>()
+            + size_of::<ExtendedContext>()
+            + size_of::<SignalMask>() // old_mask
+            + size_of::<u32>(); // `sa_handler` argument: `signum`
+
+        match self {
+            SignalAction::Default | SignalAction::Ignore => {
+                unreachable!("Default and Ignore actions should not be handled here")
+            }
+            // We don't accept signal handlers with no signal restorers for now.
+            SignalAction::SimpleHandler { restorer: None, .. } => Err(ENOSYS),
+            SignalAction::SimpleHandler {
+                handler,
+                restorer: Some(restorer),
+                ..
+            } => {
+                // Save current interrupt context to 128 bytes above current user stack
+                // and align to 16 bytes. Then we push the return address of the restorer.
+                // TODO!!!: Determine the size of the return address
+                let sp = VAddr::from(int_stack.rsp as usize - 128 - CONTEXT_SIZE).floor_to(16)
+                    - size_of::<u32>();
+                let restorer_address = usize::from(restorer) as u32;
+                let mut stack =
+                    UserBuffer::new(usize::from(sp) as *mut u8, CONTEXT_SIZE + size_of::<u32>())?;
+
+                stack.copy(&restorer_address)?.ok_or(EFAULT)?; // Restorer address
+                stack.copy(&u32::from(signal))?.ok_or(EFAULT)?; // `signum`
+                stack.copy(&old_mask)?.ok_or(EFAULT)?; // Original signal mask
+                stack.copy(ext_ctx)?.ok_or(EFAULT)?; // MMX registers
+                stack.copy(int_stack)?.ok_or(EFAULT)?; // Interrupt stack
+
+                int_stack.rip = usize::from(handler) as u64;
+                int_stack.rsp = usize::from(sp) as u64;
+                Ok(())
+            }
+        }
+    }
+}
+
+impl Clone for SignalActionList {
+    fn clone(&self) -> Self {
+        Self {
+            actions: self.actions.clone(),
+        }
+    }
+}
+
+impl Default for SignalAction {
+    fn default() -> Self {
+        Self::Default
+    }
+}
+
+impl TryFromSigAction for SignalAction {
+    type Error = u32;
+
+    fn default() -> Self {
+        Self::Default
+    }
+
+    fn ignore() -> Self {
+        Self::Ignore
+    }
+
+    fn new() -> Self {
+        Self::SimpleHandler {
+            handler: VAddr(0),
+            restorer: None,
+            mask: SignalMask::empty(),
+        }
+    }
+
+    fn set_siginfo(self) -> Result<Self, Self::Error> {
+        Err(EINVAL)
+    }
+
+    fn handler(mut self, handler_addr: usize) -> Result<Self, Self::Error> {
+        if let Self::SimpleHandler { handler, .. } = &mut self {
+            *handler = VAddr(handler_addr);
+            Ok(self)
+        } else {
+            unreachable!()
+        }
+    }
+
+    fn restorer(mut self, restorer_addr: usize) -> Result<Self, Self::Error> {
+        if let Self::SimpleHandler { restorer, .. } = &mut self {
+            *restorer = NonZero::new(restorer_addr).map(|x| VAddr(x.get()));
+            Ok(self)
+        } else {
+            unreachable!()
+        }
+    }
+
+    fn mask(mut self, mask_value: u64) -> Result<Self, Self::Error> {
+        if let Self::SimpleHandler { mask, .. } = &mut self {
+            *mask = SignalMask::from(mask_value);
+            Ok(self)
+        } else {
+            unreachable!()
+        }
+    }
+}
+
+impl From<SignalAction> for SigAction {
+    fn from(action: SignalAction) -> SigAction {
+        match action {
+            SignalAction::Default => SigAction::default(),
+            SignalAction::Ignore => SigAction::ignore(),
+            SignalAction::SimpleHandler {
+                handler,
+                restorer,
+                mask,
+            } => {
+                let action = SigAction::new()
+                    .handler(usize::from(handler))
+                    .mask(u64::from(mask));
+
+                if let Some(restorer) = restorer {
+                    action.restorer(usize::from(restorer))
+                } else {
+                    action
+                }
+            }
+        }
+    }
+}

+ 40 - 0
src/kernel/task/signal/signal_mask.rs

@@ -0,0 +1,40 @@
+use super::Signal;
+
+#[derive(Debug, Clone, Copy)]
+pub struct SignalMask(u64);
+
+impl SignalMask {
+    pub(super) const fn new(mask: u64) -> Self {
+        Self(mask)
+    }
+
+    pub(super) const fn empty() -> Self {
+        Self(0)
+    }
+
+    pub fn mask(&mut self, mask: Self) {
+        self.0 |= mask.0;
+    }
+
+    pub fn unmask(&mut self, mask: Self) {
+        self.0 &= !mask.0;
+    }
+
+    pub fn include(&self, signal: Signal) -> bool {
+        let signal_mask = Self::from(signal);
+        self.0 & signal_mask.0 != 0
+    }
+}
+
+impl From<SignalMask> for u64 {
+    fn from(value: SignalMask) -> Self {
+        let SignalMask(mask) = value;
+        mask
+    }
+}
+
+impl From<u64> for SignalMask {
+    fn from(mask: u64) -> Self {
+        Self(mask)
+    }
+}