From e0ecd1977cfb1ba734c121a753251fbc422aed36 Mon Sep 17 00:00:00 2001 From: SuchAFuriousDeath <48620541+SuchAFuriousDeath@users.noreply.github.com> Date: Sat, 24 Feb 2024 15:49:11 +0100 Subject: [PATCH] Wrapper type for signals, refactor errors and signal numbers (#595) Co-authored-by: tompro --- src/kernel/src/errno.rs | 323 ++++++++++++------------------- src/kernel/src/process/mod.rs | 14 +- src/kernel/src/process/signal.rs | 29 ++- src/kernel/src/signal/mod.rs | 178 ++++++++++------- src/kernel/src/signal/set.rs | 34 ++-- 5 files changed, 265 insertions(+), 313 deletions(-) diff --git a/src/kernel/src/errno.rs b/src/kernel/src/errno.rs index 9f8454ee5..87d404f65 100644 --- a/src/kernel/src/errno.rs +++ b/src/kernel/src/errno.rs @@ -4,105 +4,126 @@ use std::num::NonZeroI32; // This file contains errno used in a PS4 system. The value of each errno must be the same as the // PS4. -pub const EPERM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(1) }; -pub const ENOENT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(2) }; -pub const ESRCH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(3) }; -pub const EINTR: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(4) }; -pub const EIO: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(5) }; -pub const ENXIO: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(6) }; -pub const E2BIG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(7) }; -pub const ENOEXEC: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(8) }; -pub const EBADF: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(9) }; -pub const ECHILD: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(10) }; -pub const EDEADLK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(11) }; -pub const ENOMEM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(12) }; -pub const EACCES: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(13) }; -pub const EFAULT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(14) }; -pub const ENOTBLK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(15) }; -pub const EBUSY: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(16) }; -pub const EEXIST: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(17) }; -pub const EXDEV: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(18) }; -pub const ENODEV: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(19) }; -pub const ENOTDIR: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(20) }; -pub const EISDIR: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(21) }; -pub const EINVAL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(22) }; -pub const ENFILE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(23) }; -pub const EMFILE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(24) }; -pub const ENOTTY: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(25) }; -pub const ETXTBSY: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(26) }; -pub const EFBIG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(27) }; -pub const ENOSPC: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(28) }; -pub const ESPIPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(29) }; -pub const EROFS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(30) }; -pub const EMLINK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(31) }; -pub const EPIPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(32) }; -pub const EDOM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(33) }; -pub const ERANGE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(34) }; -pub const EAGAIN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(35) }; -pub const EINPROGRESS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(36) }; -pub const EALREADY: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(37) }; -pub const ENOTSOCK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(38) }; -pub const EDESTADDRREQ: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(39) }; -pub const EMSGSIZE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(40) }; -pub const EPROTOTYPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(41) }; -pub const ENOPROTOOPT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(42) }; -pub const EPROTONOSUPPORT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(43) }; -pub const ESOCKTNOSUPPORT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(44) }; -pub const EOPNOTSUPP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(45) }; -pub const EPFNOSUPPORT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(46) }; -pub const EAFNOSUPPORT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(47) }; -pub const EADDRINUSE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(48) }; -pub const EADDRNOTAVAIL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(49) }; -pub const ENETDOWN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(50) }; -pub const ENETUNREACH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(51) }; -pub const ENETRESET: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(52) }; -pub const ECONNABORTED: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(53) }; -pub const ECONNRESET: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(54) }; -pub const ENOBUFS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(55) }; -pub const EISCONN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(56) }; -pub const ENOTCONN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(57) }; -pub const ESHUTDOWN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(58) }; -pub const ETOOMANYREFS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(59) }; -pub const ETIMEDOUT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(60) }; -pub const ECONNREFUSED: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(61) }; -pub const ELOOP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(62) }; -pub const ENAMETOOLONG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(63) }; -pub const EHOSTDOWN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(64) }; -pub const EHOSTUNREACH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(65) }; -pub const ENOTEMPTY: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(66) }; -pub const EPROCLIM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(67) }; -pub const EUSERS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(68) }; -pub const EDQUOT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(69) }; -pub const ESTALE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(70) }; -pub const EREMOTE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(71) }; -pub const EBADRPC: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(72) }; -pub const ERPCMISMATCH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(73) }; -pub const EPROGUNAVAIL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(74) }; -pub const EPROGMISMATCH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(75) }; -pub const EPROCUNAVAIL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(76) }; -pub const ENOLCK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(77) }; -pub const ENOSYS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(78) }; -pub const EFTYPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(79) }; -pub const EAUTH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(80) }; -pub const ENEEDAUTH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(81) }; -pub const EIDRM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(82) }; -pub const ENOMSG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(83) }; -pub const EOVERFLOW: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(84) }; -pub const ECANCELED: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(85) }; -pub const EILSEQ: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(86) }; -pub const ENOATTR: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(87) }; -pub const EDOOFUS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(88) }; -pub const EBADMSG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(89) }; -pub const EMULTIHOP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(90) }; -pub const ENOLINK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(91) }; -pub const EPROTO: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(92) }; -pub const ENOTCAPABLE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(93) }; -pub const ECAPMODE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(94) }; -pub const ENOBLK: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(95) }; -pub const EICV: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(96) }; -pub const ENOPLAYGOENT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(97) }; -pub const EREVOKE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(98) }; -pub const ESDKVERSION: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(99) }; +macro_rules! error_numbers { + ($($name:ident($num:expr) => $desc:literal,)*) => { + $( + #[allow(dead_code)] + pub const $name: NonZeroI32 = unsafe { + assert!($num > 0); + NonZeroI32::new_unchecked($num) + }; + )* + + fn strerror_impl(num: NonZeroI32) -> &'static str { + match num { + $( $name => $desc, )* + _ => todo!("strerror {num}", num = num.get()), + } + } + }; +} + +error_numbers! { + EPERM(1) => "operation not permitted", + ENOENT(2) => "no such file or directory", + ESRCH(3) => "no such process", + EINTR(4) => "interrupted system call", + EIO(5) => "input/output error", + ENXIO(6) => "device not configured", + E2BIG(7) => "argument list too long", + ENOEXEC(8) => "exec format error", + EBADF(9) => "bad file descriptor", + ECHILD(10) => "no child processes", + EDEADLK(11) => "resource deadlock avoided", + ENOMEM(12) => "cannot allocate memory", + EACCES(13) => "permission denied", + EFAULT(14) => "bad address", + ENOTBLK(15) => "block device required", + EBUSY(16) => "device busy", + EEXIST(17) => "file exists", + EXDEV(18) => "cross-device link", + ENODEV(19) => "operation not supported by device", + ENOTDIR(20) => "not a directory", + EISDIR(21) => "is a directory", + EINVAL(22) => "invalid argument", + ENFILE(23) => "too many open files in system", + EMFILE(24) => "too many open files", + ENOTTY(25) => "inappropriate ioctl for device", + ETXTBSY(26) => "text file busy", + EFBIG(27) => "file too large", + ENOSPC(28) => "no space left on device", + ESPIPE(29) => "illegal seek", + EROFS(30) => "read-only filesystem", + EMLINK(31) => "too many links", + EPIPE(32) => "broken pipe", + EDOM(33) => "numerical argument out of domain", + ERANGE(34) => "result too large", + EAGAIN(35) => "resource temporarily unavailable", + EINPROGRESS(36) => "operation now in progress", + EALREADY(37) => "operation already in progress", + ENOTSOCK(38) => "socket operation on non-socket", + EDESTADDRREQ(39) => "destination address required", + EMSGSIZE(40) => "message too long", + EPROTOTYPE(41) => "protocol wrong type for socket", + ENOPROTOOPT(42) => "protocol not available", + EPROTONOSUPPORT(43) => "protocol not supported", + ESOCKTNOSUPPORT(44) => "socket type not supported", + EOPNOTSUPP(45) => "operation not supported", + EPFNOSUPPORT(46) => "protocol family not supported", + EAFNOSUPPORT(47) => "address family not supported by protocol", + EADDRINUSE(48) => "address already in use", + EADDRNOTAVAIL(49) => "can't assign requested address", + ENETDOWN(50) => "network is down", + ENETUNREACH(51) => "network is unreachable", + ENETRESET(52) => "network dropped connection on reset", + ECONNABORTED(53) => "software caused connection abort", + ECONNRESET(54) => "connection reset by peer", + ENOBUFS(55) => "no buffer space available", + EISCONN(56) => "socket is already connected", + ENOTCONN(57) => "socket is not connected", + ESHUTDOWN(58) => "can't send after socket shutdown", + ETOOMANYREFS(59) => "too many references: can't splice", + ETIMEDOUT(60) => "operation timed out", + ECONNREFUSED(61) => "connection refused", + ELOOP(62) => "too many levels of symbolic links", + ENAMETOOLONG(63) => "file name too long", + EHOSTDOWN(64) => "host is down", + EHOSTUNREACH(65) => "no route to host", + ENOTEMPTY(66) => "directory not empty", + EPROCLIM(67) => "too many processes", + EUSERS(68) => "too many users", + EDQUOT(69) => "disc quota exceeded", + ESTALE(70) => "stale NFS file handle", + EREMOTE(71) => "too many levels of remote in path", + EBADRPC(72) => "RPC struct is bad", + ERPCMISMATCH(73) => "RPC version wrong", + EPROGUNAVAIL(74) => "RPC prog. not avail.", + EPROGMISMATCH(75) => "program version wrong", + EPROCUNAVAIL(76) => "bad procedure for program", + ENOLCK(77) => "no locks available", + ENOSYS(78) => "function not implemented", + EFTYPE(79) => "inappropriate file type or format", + EAUTH(80) => "authentication error", + ENEEDAUTH(81) => "need authenticator", + EIDRM(82) => "identifier removed", + ENOMSG(83) => "no message of desired type", + EOVERFLOW(84) => "value too large to be stored in data type", + ECANCELED(85) => "operation canceled", + EILSEQ(86) => "illegal byte sequence", + ENOATTR(87) => "attribute not found", + EDOOFUS(88) => "function or API is being abused at run-time", + EBADMSG(89) => "bad message", + EMULTIHOP(90) => "multihop attempted", + ENOLINK(91) => "link has been severed", + EPROTO(92) => "protocol error", + ENOTCAPABLE(93) => "capabilities insufficient", + ECAPMODE(94) => "not permitted in capability mode", + ENOBLK(95) => "block not ready", + EICV(96) => "integrity check error", + ENOPLAYGOENT (97) => "file not found in PlayGo chunk definition file", + EREVOKE(98) => "file is revoked", + ESDKVERSION(99) => "SDK version of a binary file is invalid", +} /// An object that is mappable to PS4 errno. pub trait Errno: Error { @@ -123,108 +144,8 @@ impl From for Box { /// Get human readable text. pub fn strerror(num: NonZeroI32) -> &'static str { - match num { - EPERM => "operation not permitted", - ENOENT => "no such file or directory", - ESRCH => "no such process", - EINTR => "interrupted system call", - EIO => "input/output error", - ENXIO => "device not configured", - E2BIG => "argument list too long", - ENOEXEC => "exec format error", - EBADF => "bad file descriptor", - ECHILD => "no child processes", - EDEADLK => "resource deadlock avoided", - ENOMEM => "cannot allocate memory", - EACCES => "permission denied", - EFAULT => "bad address", - ENOTBLK => "block device required", - EBUSY => "device busy", - EEXIST => "file exists", - EXDEV => "cross-device link", - ENODEV => "operation not supported by device", - ENOTDIR => "not a directory", - EISDIR => "is a directory", - EINVAL => "invalid argument", - ENFILE => "too many open files in system", - EMFILE => "too many open files", - ENOTTY => "inappropriate ioctl for device", - ETXTBSY => "text file busy", - EFBIG => "file too large", - ENOSPC => "no space left on device", - ESPIPE => "illegal seek", - EROFS => "read-only filesystem", - EMLINK => "too many links", - EPIPE => "broken pipe", - EDOM => "numerical argument out of domain", - ERANGE => "result too large", - EAGAIN => "resource temporarily unavailable", - EINPROGRESS => "operation now in progress", - EALREADY => "operation already in progress", - ENOTSOCK => "socket operation on non-socket", - EDESTADDRREQ => "destination address required", - EMSGSIZE => "message too long", - EPROTOTYPE => "protocol wrong type for socket", - ENOPROTOOPT => "protocol not available", - EPROTONOSUPPORT => "protocol not supported", - ESOCKTNOSUPPORT => "socket type not supported", - EOPNOTSUPP => "operation not supported", - EPFNOSUPPORT => "protocol family not supported", - EAFNOSUPPORT => "address family not supported by protocol family", - EADDRINUSE => "address already in use", - EADDRNOTAVAIL => "can't assign requested address", - ENETDOWN => "network is down", - ENETUNREACH => "network is unreachable", - ENETRESET => "network dropped connection on reset", - ECONNABORTED => "software caused connection abort", - ECONNRESET => "connection reset by peer", - ENOBUFS => "no buffer space available", - EISCONN => "socket is already connected", - ENOTCONN => "socket is not connected", - ESHUTDOWN => "can't send after socket shutdown", - ETOOMANYREFS => "too many references: can't splice", - ETIMEDOUT => "operation timed out", - ECONNREFUSED => "connection refused", - ELOOP => "too many levels of symbolic links", - ENAMETOOLONG => "file name too long", - EHOSTDOWN => "host is down", - EHOSTUNREACH => "no route to host", - ENOTEMPTY => "directory not empty", - EPROCLIM => "too many processes", - EUSERS => "too many users", - EDQUOT => "disc quota exceeded", - ESTALE => "stale NFS file handle", - EREMOTE => "too many levels of remote in path", - EBADRPC => "RPC struct is bad", - ERPCMISMATCH => "RPC version wrong", - EPROGUNAVAIL => "RPC prog. not avail", - EPROGMISMATCH => "program version wrong", - EPROCUNAVAIL => "bad procedure for program", - ENOLCK => "no locks available", - ENOSYS => "function not implemented", - EFTYPE => "inappropriate file type or format", - EAUTH => "authentication error", - ENEEDAUTH => "need authenticator", - EIDRM => "identifier removed", - ENOMSG => "no message of desired type", - EOVERFLOW => "value too large to be stored in data type", - ECANCELED => "operation canceled", - EILSEQ => "illegal byte sequence", - ENOATTR => "attribute not found", - EDOOFUS => "function or API is being abused at run-time", - EBADMSG => "bad message", - EMULTIHOP => "multi-hop attempted", - ENOLINK => "link has been severed", - EPROTO => "protocol error", - ENOTCAPABLE => "capabilities insufficient", - ECAPMODE => "not permitted in capability mode", - ENOBLK => "block not ready", - EICV => "integrity check error", - ENOPLAYGOENT => "file not found in PlayGo chunk definition file", - EREVOKE => "file is revoked", - ESDKVERSION => "SDK version of a binary file is invalid", - v => todo!("strerror {v}"), - } + // This function is generated inside the macro `error_numbers!`. + strerror_impl(num) } impl Errno for Infallible { diff --git a/src/kernel/src/process/mod.rs b/src/kernel/src/process/mod.rs index b4fee6d61..14e3eec8a 100644 --- a/src/kernel/src/process/mod.rs +++ b/src/kernel/src/process/mod.rs @@ -12,11 +12,11 @@ use crate::errno::{EINVAL, ENAMETOOLONG, EPERM, ERANGE, ESRCH}; use crate::fs::Vnode; use crate::idt::Idt; use crate::info; -use crate::signal::SigChldFlags; use crate::signal::{ strsignal, SignalAct, SignalFlags, SignalSet, SIGCHLD, SIGKILL, SIGSTOP, SIG_BLOCK, SIG_DFL, - SIG_IGN, SIG_MAXSIG, SIG_SETMASK, SIG_UNBLOCK, + SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, }; +use crate::signal::{SigChldFlags, Signal}; use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls}; use crate::ucred::{AuthInfo, Gid, Privilege, Ucred, Uid}; use gmtx::{Gutex, GutexGroup, GutexWriteGuard}; @@ -281,15 +281,13 @@ impl VProc { fn sys_sigaction(self: &Arc, _: &VThread, i: &SysIn) -> Result { // Get arguments. - let sig: i32 = i.args[0].try_into().unwrap(); + let sig = { + let sig: i32 = i.args[0].try_into().unwrap(); + Signal::new(sig).ok_or(SysErr::Raw(EINVAL))? + }; let act: *const SignalAct = i.args[1].into(); let oact: *mut SignalAct = i.args[2].into(); - if sig == 0 || sig > SIG_MAXSIG { - return Err(SysErr::Raw(EINVAL)); - } - let sig = NonZeroI32::new(sig).unwrap(); - // Save the old actions. let mut acts = self.sigacts.write(); diff --git a/src/kernel/src/process/signal.rs b/src/kernel/src/process/signal.rs index 7036844ee..483158b68 100644 --- a/src/kernel/src/process/signal.rs +++ b/src/kernel/src/process/signal.rs @@ -1,5 +1,4 @@ -use crate::signal::{SigChldFlags, SignalFlags, SignalSet, SIGCHLD, SIG_MAXSIG}; -use std::num::NonZeroI32; +use crate::signal::{SigChldFlags, Signal, SignalFlags, SignalSet, SIGCHLD, SIG_MAXSIG}; /// An implementation of `sigacts` structure. #[derive(Debug)] @@ -32,51 +31,51 @@ impl SignalActs { } } - pub fn handler(&self, sig: NonZeroI32) -> usize { + pub fn handler(&self, sig: Signal) -> usize { self.handler[(sig.get() - 1) as usize] } - pub fn set_handler(&mut self, sig: NonZeroI32, h: usize) { + pub fn set_handler(&mut self, sig: Signal, h: usize) { self.handler[(sig.get() - 1) as usize] = h; } - pub fn catchmask(&self, sig: NonZeroI32) -> SignalSet { + pub fn catchmask(&self, sig: Signal) -> SignalSet { self.catchmask[(sig.get() - 1) as usize] } - pub fn set_catchmask(&mut self, sig: NonZeroI32, mask: SignalSet) { + pub fn set_catchmask(&mut self, sig: Signal, mask: SignalSet) { self.catchmask[(sig.get() - 1) as usize] = mask; } - pub fn remove_stack(&mut self, sig: NonZeroI32) { + pub fn remove_stack(&mut self, sig: Signal) { self.stack.remove(sig); } - pub fn set_interupt(&mut self, sig: NonZeroI32) { + pub fn set_interupt(&mut self, sig: Signal) { self.interupt.add(sig); } - pub fn remove_reset(&mut self, sig: NonZeroI32) { + pub fn remove_reset(&mut self, sig: Signal) { self.reset.remove(sig); } - pub fn remove_nodefer(&mut self, sig: NonZeroI32) { + pub fn remove_nodefer(&mut self, sig: Signal) { self.nodefer.remove(sig); } - pub fn set_modern(&mut self, sig: NonZeroI32) { + pub fn set_modern(&mut self, sig: Signal) { self.modern.add(sig); } - pub fn remove_ignore(&mut self, sig: NonZeroI32) { + pub fn remove_ignore(&mut self, sig: Signal) { self.ignore.remove(sig); } - pub fn set_catch(&mut self, sig: NonZeroI32) { + pub fn set_catch(&mut self, sig: Signal) { self.catch.add(sig); } - pub fn remove_catch(&mut self, sig: NonZeroI32) { + pub fn remove_catch(&mut self, sig: Signal) { self.catch.remove(sig); } @@ -88,7 +87,7 @@ impl SignalActs { self.flag = flag; } - pub fn signal_flags(&self, sig: NonZeroI32) -> SignalFlags { + pub fn signal_flags(&self, sig: Signal) -> SignalFlags { let mut flags: SignalFlags = SignalFlags::empty(); if self.stack.contains(sig) { diff --git a/src/kernel/src/signal/mod.rs b/src/kernel/src/signal/mod.rs index e13403cc2..805962e66 100644 --- a/src/kernel/src/signal/mod.rs +++ b/src/kernel/src/signal/mod.rs @@ -7,42 +7,84 @@ use std::num::NonZeroI32; mod set; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Signal(NonZeroI32); + +impl Signal { + pub const fn new(raw: i32) -> Option { + match raw { + 1..=SIG_MAXSIG => Some(Signal(unsafe { NonZeroI32::new_unchecked(raw) })), + _ => None, + } + } + + pub fn get(&self) -> i32 { + self.0.get() + } +} + +macro_rules! signals { + ($($name:ident($num:expr),)*) => { + $( + #[allow(dead_code)] + pub const $name: Signal = match Signal::new($num) { + Some(sig) => sig, + None => panic!(), + }; + )* + + fn strsignal_impl(sig: Signal) -> Cow<'static, str> { + match sig.0.get() { + $( $num => Cow::Borrowed(stringify!($name)), )* + _ => format!("{sig}", sig = sig.get()).into(), + } + } + }; +} + // List of PS4 signals. The value must be the same as PS4 kernel. -pub const SIGHUP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(1) }; -pub const SIGINT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(2) }; -pub const SIGQUIT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(3) }; -pub const SIGILL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(4) }; -pub const SIGTRAP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(5) }; -pub const SIGABRT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(6) }; -pub const SIGEMT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(7) }; -pub const SIGFPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(8) }; -pub const SIGKILL: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(9) }; -pub const SIGBUS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(10) }; -pub const SIGSEGV: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(11) }; -pub const SIGSYS: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(12) }; -pub const SIGPIPE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(13) }; -pub const SIGALRM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(14) }; -pub const SIGTERM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(15) }; -pub const SIGURG: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(16) }; -pub const SIGSTOP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(17) }; -pub const SIGTSTP: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(18) }; -pub const SIGCONT: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(19) }; -pub const SIGCHLD: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(20) }; -pub const SIGTTIN: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(21) }; -pub const SIGTTOU: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(22) }; -pub const SIGIO: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(23) }; -pub const SIGXCPU: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(24) }; -pub const SIGXFSZ: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(25) }; -pub const SIGVTALRM: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(26) }; -pub const SIGPROF: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(27) }; -pub const SIGWINCH: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(28) }; -pub const SIGINFO: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(29) }; -pub const SIGUSR1: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(30) }; -pub const SIGUSR2: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(31) }; -pub const SIGTHR: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(32) }; -pub const SIGNONE: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(128) }; -pub const SIG_MAXSIG: i32 = 128; +signals! { + SIGHUP(1), + SIGINT(2), + SIGQUIT(3), + SIGILL(4), + SIGTRAP(5), + SIGABRT(6), + SIGEMT(7), + SIGFPE(8), + SIGKILL(9), + SIGBUS(10), + SIGSEGV(11), + SIGSYS(12), + SIGPIPE(13), + SIGALRM(14), + SIGTERM(15), + SIGURG(16), + SIGSTOP(17), + SIGTSTP(18), + SIGCONT(19), + SIGCHLD(20), + SIGTTIN(21), + SIGTTOU(22), + SIGIO(23), + SIGXCPU(24), + SIGXFSZ(25), + SIGVTALRM(26), + SIGPROF(27), + SIGWINCH(28), + SIGINFO(29), + SIGUSR1(30), + SIGUSR2(31), + SIGTHR(32), + SIGNONE(128), +} + +pub fn strsignal(sig: Signal) -> Cow<'static, str> { + // This function is generated inside the macro `signals!`. + strsignal_impl(sig) +} +pub const SIG_MAXSIG: i32 = 128; // List of sigprocmask operations. The value must be the same as PS4 kernel. pub const SIG_BLOCK: i32 = 1; pub const SIG_UNBLOCK: i32 = 2; @@ -51,42 +93,38 @@ pub const SIG_SETMASK: i32 = 3; pub const SIG_IGN: usize = 1; pub const SIG_DFL: usize = 0; -pub fn strsignal(num: NonZeroI32) -> Cow<'static, str> { - match num { - SIGHUP => "SIGHUP".into(), - SIGINT => "SIGINT".into(), - SIGQUIT => "SIGQUIT".into(), - SIGILL => "SIGILL".into(), - SIGTRAP => "SIGTRAP".into(), - SIGABRT => "SIGABRT".into(), - SIGEMT => "SIGEMT".into(), - SIGFPE => "SIGFPE".into(), - SIGKILL => "SIGKILL".into(), - SIGBUS => "SIGBUS".into(), - SIGSEGV => "SIGSEGV".into(), - SIGSYS => "SIGSYS".into(), - SIGPIPE => "SIGPIPE".into(), - SIGALRM => "SIGALRM".into(), - SIGTERM => "SIGTERM".into(), - SIGURG => "SIGURG".into(), - SIGSTOP => "SIGSTOP".into(), - SIGTSTP => "SIGTSTP".into(), - SIGCONT => "SIGCONT".into(), - SIGCHLD => "SIGCHLD".into(), - SIGTTIN => "SIGTTIN".into(), - SIGTTOU => "SIGTTOU".into(), - SIGIO => "SIGIO".into(), - SIGXCPU => "SIGXCPU".into(), - SIGXFSZ => "SIGXFSZ".into(), - SIGVTALRM => "SIGVTALRM".into(), - SIGPROF => "SIGPROF".into(), - SIGWINCH => "SIGWINCH".into(), - SIGINFO => "SIGINFO".into(), - SIGUSR1 => "SIGUSR1".into(), - SIGUSR2 => "SIGUSR2".into(), - SIGTHR => "SIGTHR".into(), - SIGNONE => "SIGNONE".into(), - v => format!("{v}").into(), +/// An iterator over all possible signals +pub struct SignalIter { + current: i32, +} + +impl SignalIter { + pub fn new() -> Self { + Self { current: 1 } + } +} + +impl Iterator for SignalIter { + type Item = Signal; + + fn next(&mut self) -> Option { + if let Some(sig) = Signal::new(self.current) { + self.current += 1; + Some(sig) + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } +} + +impl ExactSizeIterator for SignalIter { + fn len(&self) -> usize { + (SIG_MAXSIG - self.current + 1) as usize } } diff --git a/src/kernel/src/signal/set.rs b/src/kernel/src/signal/set.rs index 66e2be04d..0d52a2266 100644 --- a/src/kernel/src/signal/set.rs +++ b/src/kernel/src/signal/set.rs @@ -1,6 +1,5 @@ -use super::strsignal; +use super::{strsignal, Signal, SignalIter}; use std::fmt::{Display, Formatter}; -use std::num::NonZeroI32; use std::ops::{BitAndAssign, BitOrAssign, Not}; /// An implementation of `sigset_t`. @@ -12,32 +11,33 @@ pub struct SignalSet { impl SignalSet { /// An implementation of `SIGISMEMBER`. - pub fn contains(&self, sig: NonZeroI32) -> bool { + pub fn contains(&self, sig: Signal) -> bool { (self.bits[Self::word(sig)] & Self::bit(sig)) != 0 } /// An implementation of `SIGADDSET`. - pub fn add(&mut self, sig: NonZeroI32) { + pub fn add(&mut self, sig: Signal) { self.bits[Self::word(sig)] |= Self::bit(sig); } /// An implementation of `SIGDELSET`. - pub fn remove(&mut self, sig: NonZeroI32) { + pub fn remove(&mut self, sig: Signal) { self.bits[Self::word(sig)] &= !Self::bit(sig); } // An implementation of `_SIG_IDX`. - fn idx(s: NonZeroI32) -> i32 { + fn idx(s: Signal) -> i32 { s.get() - 1 } /// An implementation of `_SIG_WORD`. - fn word(s: NonZeroI32) -> usize { - (Self::idx(s) >> 5).try_into().unwrap() + fn word(s: Signal) -> usize { + // This is safe because `Signal` is guaranteed to be non-negative. + unsafe { (Self::idx(s) >> 5).try_into().unwrap() } } /// An implementation of `_SIG_BIT`. - fn bit(s: NonZeroI32) -> u32 { + fn bit(s: Signal) -> u32 { 1 << (Self::idx(s) & 31) } } @@ -73,17 +73,13 @@ impl Display for SignalSet { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut first = true; - for i in 1..=128 { - let num = unsafe { NonZeroI32::new_unchecked(i) }; - - if self.contains(num) { - if !first { - f.write_str(" | ")?; - } - - f.write_str(strsignal(num).as_ref())?; - first = false; + for sig in SignalIter::new().filter(|sig| self.contains(*sig)) { + if !first { + f.write_str(" | ")?; } + + f.write_str(strsignal(sig).as_ref())?; + first = false; } if first {