Commit 12a2f2d7 authored by Nifou's avatar Nifou

DONE: Signals management

Now, the `sigaltstack` syscall is implemented and a alternate stack can
be defined.
A `signal` directory is created and the files for signals management are
splitted.
Features done:
*  Implement a signal queue for each process which contains all pending signals
*  Implement signal actions, a way to define a handler function for a specific signal
*  Implement signal masks, a way to block a signal from being delivered
*  Save the context and the SSE state during signal handlers
parent 11dc1f74
Pipeline #173796031 passed with stages
in 9 minutes and 45 seconds
......@@ -32,7 +32,11 @@ use crate::{
memory::MemoryArea,
scheduler::{FIRST_TIME, PROCESSES, SCHEDULER},
context::Fx,
signal::*,
signal::{
info::*,
Signal,
send_signal,
},
},
fault_code, fault_code_non_return, fault_without_code, fault_non_return, fault,
};
......
......@@ -136,6 +136,7 @@ const EXIT: usize = 60;
const WAIT4: usize = 61;
const KILL: usize = 62;
const GETCWD: usize = 79;
const SIGALTSTACK: usize = 131;
const ARCH_PRCTL: usize = 158;
const GETTID: usize = 186;
const TKILL: usize = 200;
......@@ -179,6 +180,7 @@ impl Syscall {
WAIT4 => self.wait4(args[0], args[1], args[2], args[3]),
KILL => self.kill(args[0], args[1]),
GETCWD => self.getcwd(args[0], args[1]),
SIGALTSTACK => self.sigaltstack(args[0], args[1]),
ARCH_PRCTL => self.arch_prctl(args[0], args[1]),
GETTID => self.gettid(),
TKILL => self.tkill(args[0], args[1]),
......
......@@ -35,7 +35,25 @@ use crate::{
process::{Pid, NEXT_PID},
scheduler::{exit, PROCESSES, SCHEDULER},
thread::{Thread, FX_SIZE},
signal::{Signal, SigAction, SigActionFlags, SI_TKILL, SigInfo, SigMask, send_signal_to, SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK},
signal::{
Signal,
SignalStack,
send_signal_to,
action::{
SigAction,
SigActionFlags,
},
mask::{
SigMask,
SIG_BLOCK,
SIG_UNBLOCK,
SIG_SETMASK,
},
info::{
SI_TKILL,
SigInfo,
},
},
context::Fx,
},
};
......@@ -256,6 +274,36 @@ impl Syscall {
Ok(0)
}
/// Set the stack used during a signal handler
pub fn sigaltstack(&self, ss: usize, oldss: usize) -> Result {
let mut processes = PROCESSES.write();
let current = SCHEDULER.get().current().unwrap().process;
let process = processes.get_mut(&current).unwrap();
let ss = if ss > 0 {
Some(unsafe { *(ss as *const SignalStack) })
} else {
None
};
let oldss = if oldss > 0 {
Some(unsafe { &mut *(oldss as *mut SignalStack) })
} else {
None
};
println!("sigaltstack({:?}, {:?})", ss, oldss);
if oldss.is_some() {
*oldss.unwrap() = process.signal_stack.unwrap();
}
if ss.is_some() {
process.signal_stack = ss;
}
Ok(0)
}
/// Wait for a process to change state
pub fn set_tid_addr(&self, tidptr: usize) -> Result {
/* TODO: Set tid addr */
......
......@@ -26,7 +26,15 @@ use super::{
thread::{Thread, Tid, FX_SIZE},
context::Fx,
scheduler::PROCESSES,
signal::{DEFAULT_ACTIONS, SIGDFL, SIGIGN, SigActionFlags, SigInfo, SigMask},
signal::{
action::{
DEFAULT_ACTIONS,
SIGDFL, SIGIGN,
SigActionFlags
},
info::SigInfo,
mask::SigMask,
},
info::StackWriter,
};
......@@ -105,7 +113,7 @@ pub trait SchedulerAlgo {
if action.sa_flags.contains(SigActionFlags::SA_ONSTACK) {
// Use a specially defined stack
// TODO: Signal alternate stack with if
kstack.rsp = process.signal_stack.expect("the signal stack must be initialized") as usize;
kstack.rsp = process.signal_stack.expect("the signal stack must be initialized").ss_sp as usize;
}
// Block the current signal if SA_NODEFER is not set
......
......@@ -24,7 +24,16 @@ use super::{
memory::{MemoryArea, ProcessMemory},
scheduler::{PROCESSES, SCHEDULER},
thread::{Thread, Tid},
signal::{SignalQueue, SigActions, SigMask, Signal, SigAction},
signal::{
SignalQueue,
Signal,
SignalStack,
action::{
SigAction,
SigActions,
},
mask::SigMask,
},
context::Registers,
};
use crate::memory::{self, PAGE_SIZE};
......@@ -98,7 +107,7 @@ pub struct Process {
pub actions: SigActions,
/// The stack used when a signal happens
pub signal_stack: Option<u64>,
pub signal_stack: Option<SignalStack>,
/// The saved things before the execution of the signal handler
/// * The context
......@@ -185,7 +194,11 @@ impl Process {
);
self.memory.map(area);
self.signal_stack = Some(addr + SIGNAL_STACK_SIZE as u64);
self.signal_stack = Some(SignalStack {
ss_sp: addr + SIGNAL_STACK_SIZE as u64,
ss_flags: 0,
ss_size: SIGNAL_STACK_SIZE,
});
}
/// Exit handler called when the process exits
......
......@@ -14,141 +14,46 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see https://www.gnu.org/licenses.
*/
//! Signals management
//! * Signal queues
//! * Signal actions (handlers defined when a signal occurs)
use alloc::collections::{
vec_deque::VecDeque,
btree_map::BTreeMap,
};
//! Signal actions
//! > A signal action is a handler function executed when a signal occurs.
use alloc::collections::btree_map::BTreeMap;
use lazy_static::lazy_static;
use bitflags::bitflags;
use core::{
fmt,
option::NoneError,
};
use core::fmt;
use crate::tasking::scheduler::exit;
use super::{
scheduler::{
SCHEDULER,
PROCESSES,
exit,
},
process::Pid,
Signal,
mask::SigMask,
};
/// A queue of signals
pub type SignalQueue = VecDeque<(Signal, SigInfo)>;
/// The handler of a signal
pub type SigHandler = usize;
/// Use the default signal handler (see DEFAULT_ACTIONS)
pub const SIGDFL: SigHandler = 0;
/// Ignore the signal handler
pub const SIGIGN: SigHandler = 1;
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
#[repr(usize)]
/// The list of all Linux signals
///
/// Taken from both [Wikipedia](https://en.wikipedia.org/wiki/Signal_(IPC))
/// and [the Libc manual](https://www.gnu.org/software/libc/manual/)
pub enum Signal {
/// Signals that the virtual terminal is closed
SIGHUP = 1,
/// Signals that the user wishes to interrupt the process
SIGINT,
/// Signals that the process should quit and perform a core dump
SIGQUIT,
/// Signals that the process attempts to execute an illegal, malformed, unknown, or privileged instruction
SIGILL,
/// Signals that a trap occurs. This signal is mostly raised by the `breakpoint` instruction
SIGTRAP,
/// Signals that the process must abort
SIGABRT,
/// Signals that a bus error is happening (invalid access to physical memory)
SIGBUS,
/// Signals that the process attempts to execute an erroneous arithmetic operation
SIGFPE,
/// Signals that the process MUST terminate immediately (without clean-up)
SIGKILL,
/// Do whatever you want with this signal
SIGUSR1,
/// Signals that the process attempts to use an invalid virtual memory reference
SIGSEGV,
/// Do whatever you want with this signal
SIGUSR2,
/// Signals that the process attempts to write to a pipe without a process connected to the other end
SIGPIPE,
/// Signals that a time limit is ended
SIGALRM,
/// Signals that the process should terminate (unlike SIGKILL, it can clean-up)
SIGTERM,
/// Signals a stack overflow
SIGSTKFLT,
/// Signals that a child process is terminated
SIGCHLD,
/// Resumes a stopped process
SIGCONT,
/// Stops a process
SIGSTOP,
/// A terminal has requested that a process stops
SIGTSTP,
/// Attemps to read from a terminal which is in background
SIGTTIN,
/// Attemps to write to a terminal which is in background
SIGTTOUT,
/// Happens when a socket has urgent datas
SIGURG,
/// Happens when a process has used up the CPU for a too long duration
SIGXCPU,
/// Happens when a process create a too big file
SIGXFSZ,
/// Signals that a virtual timer has expired
SIGVTALRM,
/// The handler of a signal
pub type SigHandler = usize;
/// Signals that the given time for both the process and the system is elapsed
SIGPROF,
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
/// The actions defining what to do when a signal is raised
pub struct SigActions (BTreeMap<Signal, SigAction>);
/// Signals that the window has changed its size
SIGWINCH,
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
/// This struct defines a specific action for a signal
pub struct SigAction {
/// Handler of the signal
pub sa_handler: SigHandler,
/// Signals that a file descriptor is ready to be read or write. This is mostly used for
/// sockets
SIGIO,
/// Flags of the signal
pub sa_flags: SigActionFlags,
/// Signals that a power failure is happening
SIGPWR,
/// Handler when the signal handler is done
pub sa_restorer: usize,
/// Signals that the syscall number is invalid
SIGSYS,
/// Mask of blocked signals during this signal
pub sa_mask: SigMask,
}
bitflags! {
......@@ -181,270 +86,6 @@ bitflags! {
}
}
// `sigprocmask` actions
/// Block the signal
pub const SIG_BLOCK: usize = 0;
/// Unblock the signal
pub const SIG_UNBLOCK: usize = 1;
/// Set the signal mask
pub const SIG_SETMASK: usize = 2;
bitflags! {
/// The mask of blocked signals
pub struct SigMask: usize {
#[allow(missing_docs)]
const SIGHUP = 1 << 0;
#[allow(missing_docs)]
const SIGINT = 1 << 1;
#[allow(missing_docs)]
const SIGQUIT = 1 << 2;
#[allow(missing_docs)]
const SIGILL = 1 << 3;
#[allow(missing_docs)]
const SIGTRAP = 1 << 4;
#[allow(missing_docs)]
const SIGABRT = 1 << 5;
#[allow(missing_docs)]
const SIGBUS = 1 << 6;
#[allow(missing_docs)]
const SIGFPE = 1 << 7;
#[allow(missing_docs)]
const SIGKILL = 1 << 8;
#[allow(missing_docs)]
const SIGUSR1 = 1 << 9;
#[allow(missing_docs)]
const SIGSEGV = 1 << 10;
#[allow(missing_docs)]
const SIGUSR2 = 1 << 11;
#[allow(missing_docs)]
const SIGPIPE = 1 << 12;
#[allow(missing_docs)]
const SIGALRM = 1 << 13;
#[allow(missing_docs)]
const SIGTERM = 1 << 14;
#[allow(missing_docs)]
const SIGSTKFLT = 1 << 15;
#[allow(missing_docs)]
const SIGCHLD = 1 << 16;
#[allow(missing_docs)]
const SIGCONT = 1 << 17;
#[allow(missing_docs)]
const SIGSTOP = 1 << 18;
#[allow(missing_docs)]
const SIGTSTP = 1 << 19;
#[allow(missing_docs)]
const SIGTTIN = 1 << 20;
#[allow(missing_docs)]
const SIGTTOUT = 1 << 21;
#[allow(missing_docs)]
const SIGURG = 1 << 22;
#[allow(missing_docs)]
const SIGXCPU = 1 << 23;
#[allow(missing_docs)]
const SIGXFSZ = 1 << 24;
#[allow(missing_docs)]
const SIGVTALRM = 1 << 25;
#[allow(missing_docs)]
const SIGPROF = 1 << 26;
#[allow(missing_docs)]
const SIGWINCH = 1 << 27;
#[allow(missing_docs)]
const SIGIO = 1 << 28;
#[allow(missing_docs)]
const SIGPWR = 1 << 29;
#[allow(missing_docs)]
const SIGSYS = 1 << 30;
#[allow(missing_docs)]
const SIGRTMIN = 1 << 31;
#[allow(missing_docs)]
const SIGRT_1 = 1 << 32;
#[allow(missing_docs)]
const SIGRT_2 = 1 << 33;
#[allow(missing_docs)]
const SIGRT_3 = 1 << 34;
#[allow(missing_docs)]
const SIGRT_4 = 1 << 35;
#[allow(missing_docs)]
const SIGRT_5 = 1 << 36;
#[allow(missing_docs)]
const SIGRT_6 = 1 << 37;
#[allow(missing_docs)]
const SIGRT_7 = 1 << 38;
#[allow(missing_docs)]
const SIGRT_8 = 1 << 39;
#[allow(missing_docs)]
const SIGRT_9 = 1 << 40;
#[allow(missing_docs)]
const SIGRT_10 = 1 << 41;
#[allow(missing_docs)]
const SIGRT_11 = 1 << 42;
#[allow(missing_docs)]
const SIGRT_12 = 1 << 43;
#[allow(missing_docs)]
const SIGRT_13 = 1 << 44;
#[allow(missing_docs)]
const SIGRT_14 = 1 << 45;
#[allow(missing_docs)]
const SIGRT_15 = 1 << 46;
#[allow(missing_docs)]
const SIGRT_16 = 1 << 47;
#[allow(missing_docs)]
const SIGRT_17 = 1 << 48;
#[allow(missing_docs)]
const SIGRT_18 = 1 << 49;
#[allow(missing_docs)]
const SIGRT_19 = 1 << 50;
#[allow(missing_docs)]
const SIGRT_20 = 1 << 51;
#[allow(missing_docs)]
const SIGRT_21 = 1 << 52;
#[allow(missing_docs)]
const SIGRT_22 = 1 << 53;
#[allow(missing_docs)]
const SIGRT_23 = 1 << 54;
#[allow(missing_docs)]
const SIGRT_24 = 1 << 55;
#[allow(missing_docs)]
const SIGRT_25 = 1 << 56;
#[allow(missing_docs)]
const SIGRT_26 = 1 << 57;
#[allow(missing_docs)]
const SIGRT_27 = 1 << 58;
#[allow(missing_docs)]
const SIGRT_28 = 1 << 59;
#[allow(missing_docs)]
const SIGRT_29 = 1 << 60;
#[allow(missing_docs)]
const SIGRT_30 = 1 << 61;
#[allow(missing_docs)]
const SIGRT_31 = 1 << 62;
#[allow(missing_docs)]
const SIGRT_32 = 1 << 63;
}
}
// --- SigInfo si_code values ---
// ----- Misc -----
/// Sent by kill, sigsend, raise
pub const SI_USER: usize = 0;
/// Sent by the kernel from somewhere
pub const SI_KERNEL: usize = 0x80;
/// Sent by siqueue
pub const SI_QUEUE: usize = -1isize as usize;
/// Sent by timer expiration
pub const SI_TIMER: usize = -2isize as usize;/* sent by timer expiration */
/// Sent by real time mesq state change
pub const SI_MESGQ: usize = -3isize as usize;
/// Sent by AIO completion
pub const SI_ASYNCIO: usize = -4isize as usize;/* sent by AIO completion */
/// Sent by queued SIGIO
pub const SI_SIGIO: usize = -5isize as usize;
/// Sent by tkill system call
pub const SI_TKILL: usize = -6isize as usize;
/// Sent by execve() killing subsidiary threads
pub const SI_DETHREAD: usize = -7isize as usize;
/// Sent by glibc async name lookup completion
pub const SI_ASYNCNL: usize = -60isize as usize;
/// ----- SIGSEGV -----
/// Address not mapped to object
pub const SEGV_MAPERR: usize = 1;
/// Invalid permissions for mapped object
pub const SEGV_ACCERR: usize = 2;
/// Failed address bound checks
pub const SEGV_BNDERR: usize = 3;
/// ADI not enabled for mapped object
pub const SEGV_ACCADI: usize = 5;
/// Disrupting MCD error
pub const SEGV_ADIDERR: usize = 6;
/// Precise MCD exception
pub const SEGV_ADIPERR: usize = 7;
// --- / SigInfo si_code values ---
lazy_static! {
/// The default actions
///
......@@ -511,78 +152,6 @@ lazy_static! {
};
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
/// This struct defines a specific action for a signal
pub struct SigAction {
/// Handler of the signal
pub sa_handler: SigHandler,
/// Flags of the signal
pub sa_flags: SigActionFlags,
/// Handler when the signal handler is done
pub sa_restorer: usize,
/// Mask of blocked signals during this signal
pub sa_mask: SigMask,
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
/// The actions defining what to do when a signal is raised